小和问题
在一个数组中, 每一个数左边比当前数小的数累加起来, 叫做这个数组的小和。 求一个数组的小和。
例子:[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
解题思路
使用归并排序来进行求和,在归并的时候把数组分成左右两个,在归并排序进行左右两个数组进行合并排序的时候进行计算。如果左边数组元素N,小于右边数组元素M,那么从右边数组右指针P到右边数组最后R就有(R-P+1)个N,依次累计相加,最后求出最小和。
代码
//总体思路和归并排序一致,在合并的过程中计算小和
public static int smallSum(int[] arr){
if(arr==null || arr.length<2){
return 0;
}
return mergeSort(arr,0,arr.length-1);
}
public static int mergeSort(int[] arr,int l,int r){
if(l==r){
return 0;
}
int mid=l+((r-l)>>2);
return mergeSort(arr,l,mid)
+mergeSort(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;
}
逆序对问题
在一个数组中, 左边的数如果比右边的数大, 则这两个数构成一个逆序对, 请打印所有逆序对。
解题思路
所谓逆序对就是[4,2],[4,1],[5,1]…,也就是左边比右边大,那么有多少个逆序对就是,中间位置mid减去左指针下坐标P1+1个逆序对,也就是(mid-P1+1)个逆序对,把逆序对相加进行返回就是共有多少逆序对。
代码
public static void reverseOrder(int[] arr) {
if (arr==null || arr.length<2) {
return ;
}
mergeSort(arr,0,arr.length-1);
}
public static int mergeSort(int[] arr, int l, int r) {
if (l == r) {
return 0;
}
int mid = (l+r)/2;
int k = mergeSort(arr, l, mid)+mergeSort(arr, mid+1, r)+merge(arr,l,mid,r);
System.out.println("merge总逆序数:"+k);
return k;
}
public static int merge(int[] arr, int l, int mid, int r) {
int merge_res=0;
int[] help = new int[r - l + 1]; //help的长度不是一个大的N 而是每次分治 的长度
int i=0;
int p1 = l;
int p2 = mid+1;
while(p1 <= mid && p2 <= r) {
if ( arr[p2] < arr[p1] ) { //说明p2此时比p1中剩下的元素都小
merge_res += (mid-p1+1); //核心
for(int k=0;k<mid-p1+1;k++) //打印此时的逆序对
System.out.println(arr[p1+k]+" "+arr[p2]);
}
help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++] ;
}
while(p1<=mid) {
help[i++] = arr[p1++];
}
while (p2<=r) {
help[i++] = arr[p2++];
}
//拷贝到 arr数组
for (int j = 0; j < help.length; j++) {
arr[l+j] = help[j];
}
System.out.println("merge_res:"+merge_res);
return merge_res;
}