【劍指Offer】35、數組中的逆序對


  題目描述:

  在數組中的兩個數字,如果前面一個數字大於后面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個數組中的逆序對的總數P。並將P對1000000007取模的結果輸出。 即輸出P%1000000007。

  輸入描述:

  題目保證輸入的數組中沒有的相同的數字數據范圍:

  • 對於%50的數據,size<=10^4
  • 對於%75的數據,size<=10^5
  • 對於%100的數據,size<=2*10^5

  解題思路:

  本題一個最容易想到的解法是暴力解法,順序掃描整個數組,每掃描到一個數字時,逐個比較該數字與后面的數字的大小關系,統計逆序對的個數,假設數組中有n個數字,則每個數字都要和O(n)個數字做比較,因此,這個暴力解法的時間復雜度為O(n^2)。

  一般情況下,最容易想到的往往不是最優解法。在這里,我們采用分治的思想,類比歸並排序算法來分析此題。

  首先將數組分隔成子數組,統計出子數組內部逆序對數目,然后再統計相鄰子數組之間的逆序對數目,統計過程中還需要對數組進行排序,這實際上就是歸並排序的過程。主要考慮的是合並兩個有序序列時,計算逆序對數。對於兩個有序升序序列,設置兩個下標分別指向開始位置,每次比較兩個指針對應的值,如果第一個序列當前值大於第二個序列當前值,則有第一個序列“當前長度”個逆序對。

  這看起來好像比較拗口,但是從代碼中可以直觀看出。

  舉例:

  編程實現(Java):

public class Solution {
    int res=0;
    public int InversePairs(int [] array) {
        //數組中的逆序對,歸並排序
        if(array==null || array.length==0)
            return 0;
        findInversePairs(array,0,array.length-1);
        return res%1000000007;
    }
    public void findInversePairs(int[] array,int low,int high){
        if(low<high){
            int mid=low+(high-low)/2;
            findInversePairs(array,low,mid); //左一半遞歸
            findInversePairs(array,mid+1,high); //右一半遞歸
            //merge
            merge(array,low,mid,high);
        }
    }
    public void merge(int[] array,int low,int mid,int high){
        int i=low,j=mid+1;
        int[] temp=new int[high-low+1];
        int k=0;
        while(i<=mid && j<=high){
            if(array[i]<=array[j])
                temp[k++]=array[i++];
            else {   //大於,說明是逆序
                temp[k++] = array[j++];
                res += (mid - i + 1);
                res = res%1000000007;
            }
        }
        while(i<=mid)
            temp[k++]=array[i++];
        while(j<=high)
            temp[k++]=array[j++];

        for(i=0;i<temp.length;i++)
            array[low+i]=temp[i];
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM