演算法--陣列11 逆序對+小和問題(歸併)
阿新 • • 發佈:2020-12-09
求一個數組的逆序對總數=求一個數右邊有多少個數比它小
逆序對就是一個數組中前面的值和大於後面的值的一組數。
那麼把陣列分成前後兩部分,分別進行歸併,歸併到最後merge兩個陣列,在這個過程中排序,並且計算出有多少個數是逆序的。
這樣到後來歸併兩個陣列的時候,已經知道兩個陣列各自有多少逆序對了,只需要計算歸併過程中產生的逆序對。因為已經是排序完的,所以找到第一個大於第二段中的值的時候,第二個值一定小於全部的第一段中的值,所以count要加上第一段中的剩下的所有資料。
注意兩點1.進行移位操作的時候一定記得加上括號,因為優先順序較低。
2.進行計算的時候因為資料量比較大,所以都要取餘
public class Solution {
public int InversePairs(int [] array) {
if(array==null || array.length==0){
return 0;
}
int res=mergeSort(array,0,array.length-1);
return res%1000000007;
}
public int mergeSort(int[] arr,int lo,int hi){
if(lo==hi){
return 0;
}
int mid=lo+((hi-lo)>>1);
int res1=mergeSort(arr,lo,mid)%1000000007;
int res2=mergeSort(arr,mid+1,hi)%1000000007;
int res3=merge(arr,lo,mid,hi)%1000000007;
return (res1+res2+res3)%1000000007;
}
public int merge(int[] arr,int lo,int mid,int hi){
int[] res=new int[ hi-lo+1];
int cur=0;
int cur1=lo;
int cur2=mid+1;
int count=0;
while(cur1<=mid && cur2<=hi){
if(arr[cur1]>arr[cur2]){
count+=mid-cur1+1;
count%=1000000007;
}
if(arr[cur1]<=arr[cur2]){
res[cur++]=arr[cur1++];
}else{
res[cur++]=arr[cur2++];
}
}
while(cur1<=mid){
res[cur++]=arr[cur1++];
}
while(cur2<=hi){
res[cur++]=arr[cur2++];
}
for(int i=0;i<res.length;i++){
arr[lo+i]=res[i];
}
return count;
}
}
求一個數組的小和=求一個數右邊有多少個比它大
小和就是左邊所有小於自己的和,返回一個所有數的小和之和,每次sort或者merge都產生一個小和,最終返回3個小和之和。在merge的過程中,找左邊所有小於自己的數,其實就是找右邊所有大於自己的數,也就是merge時右邊的值直接排序並跳過,左邊的值小的話就是右邊此時的剩下的值都大於左邊這個數,左邊這個數乘右邊數的數量就是左邊這個數產生的小和。
public static int smallSum(int[] a){//小和問題,就是求出一個數組的每個值的(左邊所有小於它的值和)和
//利用遞迴來解決,看成是求每個值右邊有幾個比它大的值
if(a==null &&a.length<=2)return 0;
return merge(a,0,a.length-1);
}
static int mergeSort(int[] a,int L,int R){
if(L==R)return 0;
int mid=L+((R-L)>>1);
int r1=mergeSort(a,L,mid);
int r2=mergeSort(a,mid+1,R);
int r3=merge(a,L,mid,R);
return r1+r2+r3;
}
static int merge(int[] a,int L,int mid ,int R){
int[] help=new int[R-L+1];
int p1=L;
int p2=mid+1;
int i=0;
int rst=0;
while(p1<=mid && p2<=R){
rst+=a[p1]<a[p2]?(a[p1]*(R-p2+1)):0; //注意這裡是減p2,加一才會算上另一個邊界
help[i++]=a[p1]<=a[p2]?a[p1++]:a[p2++];
}
while(p1<=mid){
help[i++]=a[p1++];
}
while(p2<=R){
help[i++]=a[p2++];
}
for(int j=0;j<help.length;j++){
a[L+j]=help[j];
}
return rst;
}