【剑指Offer】- 数组中的逆序对

题目链接:剑指Offer51
题目描述:

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

示例 1:

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

限制:

0 <= 数组长度 <= 50000

题解:

解题思路:
在排序过程中统计逆序对的数量。
归并排序:
1.递归划分。计算数组的中点middle,递归划分左数组:left = nums.slice(0, middle),递归划分右数组:right = nums.slice( middle)。递归终止条件:当数组长度为1时,终止递归。
2.合并。创建辅助数组res,设置指针cur,i,j分别指向res,左,右数组。
1)当res>left.len,左子数组已合并完,只需添加right到res中;
2)当res > right.len, 右子数组已合并完,只需添加left到res中;
3)左右数组均未合并完,比较左右数组值的大小,若左子数组<右子数组,不存在逆序,合并数组;若左子数组 > 右子数组,则存在逆序。由于子数组已有序,所以当前left[i]之后的值均 > right[j],所以逆序长度为left.len - i。


/**
 * @param {number[]} nums
 * @return {number}
 */
var reversePairs = function(nums) {
    let sum = 0;
    
    mergeSort(nums);
   

    //归并排序
    function mergeSort(nums){
        if(nums.length <= 1)
            return nums;
        let middle = Math.floor(nums.length / 2);
        let left = nums.slice(0, middle);
        let right = nums.slice(middle, nums.length);
        return merge(mergeSort(left), mergeSort(right));
    }

    //两两合并
    function merge(left, right){
        let len  = left.length + right.length;
        let res = new Array(len).fill(0);
       for(let cur = 0, i = 0, j = 0; cur < len; cur++)
        {
            if(i >= left.length)
                res[cur] = right[j++];
            else if(j >= right.length)
                res[cur] = left[i++];
            else if(left[i] <= right[j])
                res[cur] = left[i++];
            else
            {
                res[cur] = right[j++];
                // left[i] > right[j]的情况, 即left[i, end)和right[j]都是逆序对
                sum += left.length - i;
            }
        }
        return res;
    }
    return sum;
};

posted @ 2022-03-29 12:58  张宵  阅读(27)  评论(0编辑  收藏  举报