剑指offer_51_数组中的逆序对【javascript】

45 阅读1分钟

题目链接

leetcode.cn/problems/sh…

题目(困难)

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。例如,在数组{7, 5, 6, 4}中,一共存在5个逆序对,分别是(7,6),(7,5),(7,4),(6,4),(5,4)。

题解

归并排序

  • 时间复杂度:同归并排序 O(nlogn)。
  • 空间复杂度:同归并排序 O(n),因为归并排序需要用到一个临时数组。
/**
 * @param {number[]} nums
 * @return {number}
 */

var reversePairs = function (nums) {
  let count = 0;
  // 如果数组中只有1个元素或者为空,则不存在逆序对
  if (nums.length < 2) return count;

  const mergeSort = (front, behind) => {
    // 如果前后指针相遇,则归并区间只剩下一个元素了
    if (front == behind) return [nums[front]];
    let mid = front + ((behind - front) >> 1);
    // 规则让左半部分不包含中心元素 右半部分包含中心元素
    let left = mergeSort(front, mid);
    let right = mergeSort(mid + 1, behind);
    let temp = new Array(behind - front + 1).fill(0);
    // 合并有三个指针
    let cur = 0,
      l = 0,
      r = 0;
    while (l < left.length && r < right.length) {
      // 如果右边元素大于左边元素,将左边元素放到结果数组中
      if (right[r] >= left[l]) {
        temp[cur++] = left[l++];
      } else {
        temp[cur++] = right[r++];
        // 如果左边元素大于右边元素,那就出现了序列对了
        // 由于左右两边都是有序的,左边当前元素及之后的元素都会跟右边构建逆序对
        count += left.length - l;
      }
    }
    while (l < left.length) temp[cur++] = left[l++];
    while (r < right.length) temp[cur++] = right[r++];
    return temp;
  };

  // 左闭右闭区间
  mergeSort(0, nums.length - 1);
  return count;
};