小和问题
在一个数组中, 每一个数左边比当前数小的数累加起来, 叫做这个数组的小和。 求一个数组的小和。
例子:
[1,3,4,2,5]
1左边比1小的数, 没有;
3左边比3小的数, 1;
4左边比4小的数, 1、 3;
2左边比2小的数, 1;
5左边比5小的数, 1、 3、 4、 2;
所以小和为1+1+3+1+1+3+4+2=16
解:利用归并排序中,在进行两部分小组合并时,会在对比时,如果左边的比右边的小,则加上 右边个数个的左边的数 num * (right - y + 1)
其中的某一次对比
求小和只发生在两个小组之间。
public class LittleSum {
public int littleSum(int [] arrays){
return mergeSort(arrays, 0, arrays.length - 1);
}
public int mergeSort(int[] arrays, int left, int right){
if(left >= right){
return 0;
}
int mid = left + ((right - left) >> 1);
return mergeSort(arrays, left, mid)
+ mergeSort(arrays, mid + 1, right)
+ merge(arrays, left, mid, right);
}
public int merge(int[] arrays, int left, int mid, int right){
int sum = 0;
int[] help = new int[right - left + 1];
int i = 0;
int x = left, y = mid + 1;
while(x <= mid && y <= right){
sum += arrays[x] < arrays[y] ? arrays[x] * (right - y + 1) : 0;
help[i++] = arrays[x] < arrays[y] ? arrays[x++] : arrays[y++];
}
while(x <= mid){
help[i++] = arrays[x++];
}
while(y <= right){
help[i++] = arrays[y++];
}
i = 0;
while(i < help.length){
arrays[left + i] = help[i++];
}
return sum;
}
public static void main(String[] args){
int[] arrays = {1, 3, 4, 2, 5};
LittleSum littleSum = new LittleSum();
int sum = littleSum.littleSum(arrays);
System.out.println(sum);
}
}
逆序对问题
在一个数组中, 左边的数如果比右边的数大, 则折两个数构成一个逆序对, 请打印所有逆序对
解:逆序对的同理,在merge的过程中,比较相应的两个数,遇到arrays[x] > arrays[y] 则从x开始,到mid结束,都比arrays[y]大,都可以构成逆序对,所以只需要将它们输出即可
与小和相比,只有第一个while处不同,其余地方均没有改动
public void merge(int[] arrays, int left, int mid, int right){
int[] help = new int[right - left + 1];
int i = 0;
int x = left, y = mid + 1;
while(x <= mid && y <= right){
if(arrays[x] > arrays[y]){
for(int j = x; j <= mid; j++){
System.out.println(arrays[j] + " " + arrays[y]);
}
help[i++] = arrays[y++];
} else{
sum += arrays[x] * (right - y + 1);
help[i++] = arrays[x++];
}
}
while(x <= mid){
help[i++] = arrays[x++];
}
while(y <= right){
help[i++] = arrays[y++];
}
i = 0;
while(i < help.length){
arrays[left + i] = help[i++];
}
}
剑指offer中的逆序对:会有大小,溢出的问题,用int类型,会溢出,要用long型才可以
public class Solution {
public int InversePairs(int [] array) {
if(array == null || array.length == 0) return 0;
long res = mergeSort(array, 0, array.length - 1);
return (int)(res % 1000000007);
}
public long mergeSort(int[] array, int left, int right){
if(left >= right){
return 0;
}
int mid = ((right - left) >> 1) + left;
return mergeSort(array, left, mid)
+ mergeSort(array, mid + 1, right)
+ merge(array, left, mid, right);
}
public long merge(int[] array, int left, int mid, int right){
int[] help = new int[right - left + 1];
int i = left, j = mid + 1, flag = 0;
long res = 0;
while(i <= mid && j <= right){
if(array[i] < array[j]){
help[flag++] = array[i++];
}else {
help[flag++] = array[j++];
res = res + (mid - i + 1);
}
}
while(i <= mid){
help[flag++] = array[i++];
}
while(j <= right){
help[flag++] = array[j++];
}
for(i = 0; i < flag; i++){
array[left + i] = help[i];
}
return res;
}
}