1. 程式人生 > 其它 >演算法--陣列11 逆序對+小和問題(歸併)

演算法--陣列11 逆序對+小和問題(歸併)

技術標籤:演算法演算法排序演算法

求一個數組的逆序對總數=求一個數右邊有多少個數比它小

逆序對就是一個數組中前面的值和大於後面的值的一組數。
那麼把陣列分成前後兩部分,分別進行歸併,歸併到最後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;
    }