有苦有乐的算法 --- 小和问题
题目
一个无序数组,获取每个元素在左面比这个元素小的个数,求这些个数的和
例:
[3,2,5,1,4] ==> 6
[4,7,0,8,2,4,9,4] ==> 14
解析
准备一个无序数组,

将这个数组平均分成两部分,再把每一部分在平均分成两部分,以此类推,直到分成只剩一个数为止;

最右侧的[1,4]先合并,[1]为左部分,[4]为右部分,合并时左部分的1比右部分的4小,小和个数+1;

之后[3,2]合并,[3]为左部分,[2]为右部分,合并时左部分的[3]不比右部分的[2]小,小和个数不加;
[5,1,4]合并,[5]为左部分,[1,4]为右部分,合并时左部分[5]先和右部分的[1]比,右侧小,小和个数不加,[1]拿走,左部分[5]先和右部分的[4]比,右侧小,小和个数不加,再拿[5];

最后[2,3]和[1,4,5]合并,[2,3]为左部分,[1,4,5]为右部分,[2]比[1]大,小和个数不加[1]拿走;[2]比[4]小,右部分剩几个小和个数加多少(+2),[2]拿走;[3]比[4]小,右部分剩几个小和个数加多少(+2),[3]拿走;左部分没有数据右侧全部拿走

到此得到了所有小和个数
代码
public static int process(int[] arr, int l, int r) {
if (l == r) {
return 0;
}
int mid = l + ((r - l) >> 1);
return process(arr, l, mid) + process(arr, mid + 1, r) + merge(arr, l, mid, r);
}
public static int merge(int[] arr, int L, int m, int r) {
int[] help = new int[r - L + 1];
int i = 0;
int p1 = L;
int p2 = m + 1;
int res = 0;
while (p1 <= m && p2 <= r) {
res += arr[p1] < arr[p2] ? (r - p2 + 1) * arr[p1] : 0;
help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
}
while (p1 <= m) {
help[i++] = arr[p1++];
}
while (p2 <= r) {
help[i++] = arr[p2++];
}
for (i = 0; i < help.length; i++) {
arr[L + i] = help[i];
}
return res;
}
浙公网安备 33010602011771号