[路飞]_程序员必刷力扣题: 剑指 Offer 51. 数组中的逆序对

163 阅读2分钟

剑指 Offer 51. 数组中的逆序对

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

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

限制:

0 <= 数组长度 <= 50000

归并排序

思路

思路1:暴力求解 跟据题意简单粗暴,时间复杂度过高n2,时间超出限制

var reversePairs = function (nums) {
    var total = 0
    for (var i = 0; i < nums.length; i++) {
        var base = nums[i]
        for (var j = i; j < nums.length; j++) {
            if (base > nums[j]) {
                total++
            }
        }
    }
    return total
};

思路2:归并排序 时间复杂度nlogn

在归并排序的过程中来统计逆序对的个数

在归并过程中,需要将元素组分成两部分,中间值为mid

左侧序列为[0,mid] 右侧序列为[mid+1,len-1]

接着合并两个有序序列(两个升序序列)

例如:[1,3,5,7] [2,4,6,8]

在比较升序序列的过程中

  • 声明两个指针i和j分别指向两个序列的首位
  • 取出较小的一个放入新数组的第一位
    • 较小的值来自左侧,那么这个值不会和右侧任一以为组成逆序对
    • 较小的值来自右侧,那么左侧所有的值都会和右侧第一个值组成逆序对,此时逆序对数量为mid-i+1

这样可以看出我们可以直接在合并的过程中通过mid-i+1的方式直接计算出逆序对的个数,而无需逐个比较来统计

当i=mid+1或者j=len的时候证明一侧的序列已经全部合并,紧接着只需要将另一个序列中剩余部分合并回去即可

具体步骤:

  • 声明一个全局temp用来copy原nums中的元素,接着我们只需要操作逐步将temp中的值放回nums中
  • 声明一个merge函数用来排序l到r之间的元素,l>=r为终止条件,因为一个元素肯定是有序的
  • 将[l,r]分成两部分,[l,mid] [mid+1,r] 递归调用
  • 如果temp[i] <= temp[j],证明temp[i]不会与后面序列的任意构成逆序对,直接nums[n] = temp[i]并且i++
  • 如果temp[i] > temp[j],则左侧序列每一项都与temp[j]构成逆序对,总数res+=mid-i+1
  • 当i === (mid + 1)或者j===(r + 1)代表一侧元素全部放入nums中,只需将剩余元素放入nums中即可完成[l,r]之间的排序

最后返回累加的res

var temp = []
var reversePairs = function (nums) {

    var len = nums.length
    return merge(0, len - 1, nums)
};
var merge = function (l, r, nums) {
    // 终止条件
    if (l >= r) return 0;
    var mid = l + ((r - l) >> 1)
    var res = merge(l, mid, nums) + merge(mid + 1, r, nums)
    var i = l, j = mid + 1
    for (var m = l; m <= r; m++) {
        temp[m] = nums[m]
    }

    for (var n = l; n <= r; n++) {
        if (i === (mid + 1)) {
            nums[n] = temp[j]
            j++
        } else if (j === (r + 1)) {
            nums[n] = temp[i]
            i++
        } else if (temp[i] <= temp[j]) {
            nums[n] = temp[i]
            i++
        } else {
            nums[n] = temp[j]
            j++
            res += mid - i + 1
        }

    }
    return res
}