【排序】——数组中的逆序对

170 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

题目

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

示例 1:

输入: [7,5,6,4]
输出: 5

思路

1.归并排序在merge的过程中会把两组数从小到大排序到一个数组中

2.在merge的过程中如果nums[p1]>nums[p2],那么就是满足前面一个数大于后面的数的情况, 而在p1 ~ mid这个范围上面的数也是大于nums[p2]的(因为原来p1所在的数组部分有序)。

3.所以实际上就是在归并排序的merge中记录满足题目要求的值。

       if (nums[p1] > nums[p2]) {
                res += (mid - p1 + 1);
            }

代码

class Solution {
    int res = 0;
    public int reversePairs(int[] nums) {
        if (nums == null || nums.length < 2) return 0;
        mergeSort(nums);
        return res;
    }

    public void mergeSort(int[] nums) {
        mergeSort(nums, 0, nums.length - 1);
    }

    public void mergeSort(int[] nums, int left, int right) {
        if (left < right) {
            int mid = left + ((right - left) >> 1);
            mergeSort(nums, left, mid);
            mergeSort(nums, mid + 1, right);
            merge(nums, left, right, mid);
        }
    }

    public void merge(int[] nums, int left, int right, int mid) {
    //创建一个可以存放left ~ right的辅助数组
        int[] temp = new int[right - left + 1]; 
        int p1 = left;
        int p2 = mid + 1;
        int index = 0;//辅助变量给temp使用
        while (p1 <= mid && p2 <= right) { //两个指针有一个走到终点退出
            if (nums[p1] > nums[p2]) {
                res += (mid - p1 + 1);
            }
            //哪个数小就用哪个数并且指针向后移动
            temp[index++] = nums[p1] <= nums[p2] ? nums[p1++] : nums[p2++];
        }
        while (p1 <= mid) {  //p1没有走完的情况
            temp[index++] = nums[p1++];
        }
        while (p2 <= right) {  //p2没有走完的情况
            temp[index++] = nums[p2++];
        }
        //把值赋给原数组
        for (int i = left; i <= right; i++) {
            nums[i] = temp[i - left];
        }

    }
}