【问题标题】:Algorithm: Given an array A of numbers, create an array B where B[i] = sum(A[j]: A[j] <= A[i])算法:给定一个数字数组 A,创建一个数组 B,其中 B[i] = sum(A[j]: A[j] <= A[i])
【发布时间】:2015-06-19 05:35:12
【问题描述】:

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

方法一:对于每一个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) 中运行?

【问题讨论】:

    标签: arrays algorithm sorting cumsum


    【解决方案1】:

    用现代语言做到这一点的一种方法是使用字典:

    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] 
    

    【讨论】:

    • 善用计数字典。
    【解决方案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】:

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

      1. 将 A 复制到 A' 并排序 A', O(n lg n)
      2. 计算A'的前缀和,存储在S中,O(n)
      3. 遍历A,对于每个元素A_i,二分查找最大索引j在A'中使得A'[j] >= A_i, Ans[i] = S [j]

      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;
      }

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          【解决方案5】:

          我有简单的方法在 o(nlogn) 中执行此操作。

          • 根据数组的值按递增顺序对数组进行排序。在排序中,元素的索引应与元素一起使用。在 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]+" ");
          	}
          }

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-11-01
            • 1970-01-01
            • 2021-04-09
            • 1970-01-01
            • 2014-12-29
            • 1970-01-01
            • 1970-01-01
            • 2019-04-19
            相关资源
            最近更新 更多