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

132 阅读1分钟

题目描述

leetcode-cn.com/problems/sh…

分析

很典型的归并排序题目

利用归并排序在 merge 过程中两个区间有序的特点,进行逆序对统计

算法

归并排序

过程

统计的过程在归并排序过程中进行,因此如果只有一个元素不进行统计,返回 0

对左,右区间分别统计,加和,然后在两区间合并过程中再进行统计

原理

eg:[1, 2, 6, 7], [3, 4]

当左区间指向 6 的时候,实际上可以明白的是 6,7 两个元素都是逆序对的组成部分(和 3 组成),因此统计的数字应当加上的长度就是 mid - p1 + 1,也就是 p1 指针到最后一个元素的闭区间部分

代码

/**
 * @param {number[]} nums
 * @return {number}
 */
var reversePairs = function (nums) {
  return countResults(nums, 0, nums.length - 1)
}

function countResults(nums, l, r) {
  if (l >= r) return 0

  const temp = [],
    mid = (l + r) >> 1
  let ans = 0,
    p1 = l,
    p2 = mid + 1,
    k = 0

  ans += countResults(nums, l, mid)
  ans += countResults(nums, mid + 1, r)

  while (p1 <= mid || p2 <= r) {
    if (p2 > r || (p1 <= mid && nums[p1] <= nums[p2])) {
      temp[k++] = nums[p1++]
    } else {
      temp[k++] = nums[p2++]
      ans += mid - p1 + 1
    }
  }

  for (let i = l; i <= r; i++) {
    nums[i] = temp[i - l]
  }

  return ans
}