剑指Offer - 数组中的逆序对(Java实现)

题目描述:

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007

示例

输入 1,2,3,4,5,6,7,0
输出 7

思路分析:
方法1:
遍历数组,依次找出后面小于的数。该方法属于暴力查找,时间复杂度O(N^2),运行超时。

public class Solution {
    public int InversePairs(int [] array) {
        
        if(array == null || array.length < 2){
            return 0;
        }
        int temp = 0;
        for(int i = 0 ; i<array.length-1; i++){
            for(int j = i+1 ; j < array.length ; j++){
                if(array[i]>array[j]){
                    temp++;
                }
            }
        }
        return temp%1000000007;
    }
}

方法2:
利用归并排序的思想解决问题。
归并排序的思想是分而治之,将数组分为两段,每段分别排序,再将两段排序后的数组组合在一起形成最终的数组。
故,我们先记录第一段没有排序之前时,出现的逆序对的个数。以及第二段原数组出现逆序对的个数。再计算两段数组之间出现的逆序对的个数。三者之和即为求得的最终结果。
重点是如何计算两段数组之间出现的逆序对。
1,设置两个指针分别指向两段数组的末尾(p1表示前一段数组的指针,p2表示后一段数组的指针),再新建一个辅助数组,长度是两段数组之和。
2,比较p1和p2位置数字的大小,若arr1[p1]>arr2[p2],则p2之前的所有数字均小于p1,该值也就是p1形成的逆序对,并将arr1[p1]放入辅助数组的末尾,p1向前移动一位。若arr1[p1]<arr2[p2],则将p2指针所指的数字存入辅助数组,p2指针向前移动一位。后面的思路和归并排序就是一样了。

public class Solution {
    
    //尝试归并排序的思想。
    public int InversePairs(int [] array) {
        
        if(array == null || array.length < 2){
            return 0;
        }
        int num = merge(array,0,array.length-1);
        return num%1000000007;
    }
    public int merge(int[] arr , int l, int r){
        if(r<=l){
            return 0;
        }
        int mid =(l+r)/2;
        int leftnum = merge(arr,l,mid)%1000000007;
        int rightnum = merge(arr,mid+1,r)%1000000007;
        int mergenum = mergeSort(arr,l,mid,r);
        return (leftnum+rightnum+mergenum)%1000000007;
    }
    public int mergeSort(int[] arr, int l, int m, int r){
        int[] help = new int[r-l+1];
        int h = r-l;
        int p1 = m;
        int p2 = r;
        int count = 0;
        while(p1>=l && p2>m){
            if(arr[p1]>arr[p2]){
                count += p2-m;
                if(count>=1000000007){
                    count%=1000000007;
                }
                help[h--] = arr[p1--];
            }else{
                help[h--] = arr[p2--];
            }
        }
        while(p1>=l){
            help[h--] = arr[p1--];
        }
        while(p2>m){
            help[h--] = arr[p2--];
        }
        for(int i = 0 ; i < help.length; i++){
            arr[l+i] = help[i];
        }
        return count;
    }
}
public class Solution {
    
    //尝试归并排序的思想。
    public int InversePairs(int [] array) {
        
        if(array == null || array.length < 2){
            return 0;
        }
        int[] help = new int[array.length];
        int num = merge(array,help,0,array.length-1);
        return num%1000000007;
    }
    public int merge(int[] arr ,int[] help ,int l, int r){
        if(r<=l){
            return 0;
        }
        int mid =(l+r)/2;
        int leftnum = merge(arr,help,l,mid)%1000000007;
        int rightnum = merge(arr,help,mid+1,r)%1000000007;
        int mergenum = mergeSort(arr,help,l,mid,r);
        return (leftnum+rightnum+mergenum)%1000000007;
    }
    public int mergeSort(int[] arr, int[] help, int l, int m, int r){
        int h = r;
        int p1 = m;
        int p2 = r;
        int count = 0;
        while(p1>=l && p2>m){
            if(arr[p1]>arr[p2]){
                count += p2-m;
                if(count>=1000000007){
                    count%=1000000007;
                }
                help[h--] = arr[p1--];
            }else{
                help[h--] = arr[p2--];
            }
        }
        while(p1>=l){
            help[h--] = arr[p1--];
        }
        while(p2>m){
            help[h--] = arr[p2--];
        }
        for(int i = l ; i <= r; i++){
            arr[i] = help[i];
        }
        return count;
    }
}

猜你喜欢

转载自blog.csdn.net/justlikeu777/article/details/85109894