算法:给定一个数组A,创建一个数组B,其中B [i] = sum(A [j]:A [j] <= A [i])

时间:2015-06-19 05:35:13

标签: arrays algorithm sorting cumsum

示例:A = [4,1,3,2,3,3]。然后我们得到B = [16,1,12,3,12,12]。

方法1:对于每个i,只需搜索A并总结小于或等于A [i]的数字。粗略地说,这需要横穿A n次,因此需要花费O(n ^ 2)时间。

方法2:排序A得到A',然后找到A'的cumsum。这需要横穿A'一次。所以整体运行时间就是排序,O(n log n)。

然而,当有关系时,这不起作用。对于上面的例子,我们得到A'= [1,2,3,3,3,6],所以cumsum(A')= [1,3,6,9,12,16],这是不一样的作为B(已排序)。

有没有办法解决这个问题,以便它仍然在O(n log n)中运行?

5 个答案:

答案 0 :(得分:4)

使用现代语言的一种方法是使用词典:

A=random_integers(1,10,10)
SA=sorted(A) #O(n log n)
CSA=cumsum(SA)  #O(n)
I=dict(zip(SA,CSA)) #O(n)
B=[I[x] for x in A] #O(n)

在构建字典时,遇到的最后一个值会替换现有的值,因此至少它适合好的值。 这给了:

[7 5 4 1 4 2 6 7 8 2]
[1 2 2 4 4 5 6 7 7 8]
[1 3 5 9 13 18 24 31 38 46]
{1:1, 2:5, 4:13, 5:18, 6:24, 7:38, 8:46}
[38 18 13 1 13 5 24 38 46 5] 

答案 1 :(得分:2)

好的,如果你允许O(n log n)那么这是一个非常简单的方法来实现它:

  1. 将A复制到A'并排序A',O(n lg n)
  2. 计算A'的前缀和,将它们存储在S,O(n)
  3. 循环A,对于每个元素A_i,在A'中二进制搜索最大索引j,使得A'[j]&gt; = A_i, Ans [i ] = S [j]
  4. Ans 是您想要的数组

    下面是一个示例C ++代码说明了这个想法

    #include<bits/stdc++.h>
    using namespace std;
    
    int A[6] = {4, 1, 3, 2, 3, 3}, B[6], SUM[6] = {0}, ANS[6];
    
    int main(){
    	for(int i=0; i<6; i++) B[i] = A[i];
    	sort(B, B+6);
    	for(int i=0; i<6; i++) SUM[i] = (i? SUM[i-1]:0) + B[i];
    	
    	for(int i=0; i<6;i++){
    		int j = upper_bound(B,B+6, A[i]) - B;
    		ANS[i] = SUM[j-1];
    		printf("%d ", ANS[i]);
    	}
    	puts("");
    
    	return 0;
    }

答案 2 :(得分:2)

更好的方法可能是将A排序为A'= [1,3,6,9,12,16],然后找到整数的总和而不是cumsum,迭代数组,如下所示:

B[A.length-1] = sum;
for(int i=A.length-2; i=0; i++){
    if(A[i]!=A[i+1]){
        B[i] = sum - B[i+1];
    }
    else{
        B[i] = B[i+1];
    }
}

答案 3 :(得分:1)

在排序方法中,在存储结果之前,找到具有相同值的所有元素(现在它们都是连续的,因此这与您已经进行过的遍历相同)并将它们一起处理:计算总和(对所有人都一样),然后记录每个人的(相同)结果。

答案 4 :(得分:1)

我很容易在o(nlogn)中这样做。

  • 按递增顺序对数组的值进行排序。在元素的排序索引中应该使用element.for在java中排序你可以使用内置函数

  java.util.Arrays.sort(input, new java.util.Comparator<int[]>() {
            public int compare(int[] a, int[] b) {
                return Double.compare(a[1], b[1]);
            }
        });

  • 创建一个包含答案的临时数组。
  • 计算排序数组中所有元素的总和。
  • 从后到前遍历排序数组。
  • 维持连续相似数字的计数。
  • 当从sum-count * nextvalue获得与下一个值更新和的不同值时。
  • 将总和存储在当前值的索引处;

这是我的java代码

class Solution
{
	public static void main (String[] args) throws java.lang.Exception
	{
		int[][] input={{0,4}, {1,1}, {2,3}, {3,2}, {4,3}, {5,3
		
          //sort one column with respect to other column in 2d array
		  java.util.Arrays.sort(input, new java.util.Comparator<int[]>() {
            public int compare(int[] a, int[] b) {
                return Double.compare(a[1], b[1]);
            }
           });
        
           int[] temp=new int[6];   //Answer array
           int sum=0;
           
           for(int i=0;i<6;i++){
               sum=sum+input[i][1];
           }
           
           int count=1;
           temp[input[5][0]]=sum;
           
           for(int i=4;i>=0;i--){
               if(input[i][1]==input[i+1][1]){
                   count++;
                   temp[input[i][0]]=sum;
               }
               else{
                   sum=sum-(count*input[i+1][1]);
                   temp[input[i][0]]=sum;
                   count=1;
               }
           }
           
           for(int i=0;i<6;i++)
              System.out.print(temp[i]+" ");
	}
}