算法:给定一个数字数组 A,创建一个数组 B,其中 B[i] = sum(A[j]: A[j] <= A[i])
Algorithm: Given an array A of numbers, create an array B where B[i] = sum(A[j]: A[j] <= A[i])
示例:A = [4, 1, 3, 2, 3, 3]。然后我们得到 B = [16, 1, 12, 3, 12, 12].
方法一:对于每个i,只搜索A,将小于或等于A[i]的数相加。粗略地说,这需要遍历A n次,所以需要O(n^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) 内运行?
在排序方法中,在存储结果之前,找到所有具有相同值的元素(现在都是连续的,所以这与你已经在做的遍历相同)并一起处理它们:计算总和(所有人都相同),然后记录每个人的(相同)结果。
用现代语言做到这一点的一种方法是使用字典:
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]
我有简单的方法在 o(nlogn) 中执行此操作。
- 根据递增的值对数组进行排序 order.In 元素的排序索引应与 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]+" ");
}
}
好的,如果你允许 O(n log n)
那么这里有一个非常简单的实现方法:
- 将A复制到A'并排序A', O(n lg n)
- 计算A'的前缀和,存入S,O(n)
- 遍历 A,对于每个元素 A_i,二进制搜索 A' 中最大的 索引
j
使得 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;
}
更好的方法可能是将 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];
}
}
示例:A = [4, 1, 3, 2, 3, 3]。然后我们得到 B = [16, 1, 12, 3, 12, 12].
方法一:对于每个i,只搜索A,将小于或等于A[i]的数相加。粗略地说,这需要遍历A n次,所以需要O(n^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) 内运行?
在排序方法中,在存储结果之前,找到所有具有相同值的元素(现在都是连续的,所以这与你已经在做的遍历相同)并一起处理它们:计算总和(所有人都相同),然后记录每个人的(相同)结果。
用现代语言做到这一点的一种方法是使用字典:
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]
我有简单的方法在 o(nlogn) 中执行此操作。
- 根据递增的值对数组进行排序 order.In 元素的排序索引应与 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]+" ");
}
}
好的,如果你允许 O(n log n)
那么这里有一个非常简单的实现方法:
- 将A复制到A'并排序A', O(n lg n)
- 计算A'的前缀和,存入S,O(n)
- 遍历 A,对于每个元素 A_i,二进制搜索 A' 中最大的 索引
j
使得 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;
}
更好的方法可能是将 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];
}
}