JS 刷 Leetcode:剑指offer051.数组中的逆序对数

简介: JS 刷 Leetcode:剑指offer051.数组中的逆序对数

今天同学在群里分享了一到求逆序对数的题目,LeetCode上搜了一下有道差不多的,那我们来做一下吧。

1. 题目

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

  • 示例 1:
输入: [7,5,6,4]
输出: 5

限制:
0 <= 数组长度 <= 50000

2. 暴力梭哈法

一开始我看到这道题的反应是很简单,直接套上两个循环查喽(题目还是刷的少了2333)。

var reversePairs = function(nums) {
  const length = nums.length
  let count = 0
  for(let i = 0; i < nums.length; i++) {
    for(let l = i + 1; l < nums.length; l++) {
      if(nums[l] < nums[i]) {
        count++
      }
    }
  }
  return count
};

image.png

直接就崩了,emmm遇事不决暴力法在这里行不通呀。仔细想想数组长度最大50000,n的二次都快2.5亿次计算了,确实得蹦。

  • 分析:

    • 时间复杂度: O(n2),两个循环,n为数组的长度。
    • 空间复杂度:O(1),只用到一个临时变量。

3. 归并排序优化

使用归并排序,在合并的过程中处理逆序对数,因为在两个有序的序列里,逆序对得个数是很好算的,
可以看下面两张图

3.1 图一解释归并算法:分而治之的思想

分解 -> 排序 -> 合并
image.png

3.2 图二解释取逆序对数

从下图可以看出,每一步的排序中逆序对的个数其实就是

当左边的left[leftIndex] < right[rightIndex]时

$$ 逆序对的个数 = left数组的长度-leftIndex $$

image.png

/**
 * @param {number[]} nums
 * @return {number}
 */
var reversePairs = function(nums) {
  let count = 0 // 记录逆序对数
  const mergeSort = function(nums) {
    const length = nums.length
    if (length < 2) {
      return nums
    }
    const mid = Math.floor((length / 2))   // 获取二分位置
    const leftArr = nums.slice(0, mid)  
    const rightArr = nums.slice(mid)
    return merge(mergeSort(leftArr), mergeSort(rightArr))
  }
  
  const merge = function(leftArr, rightArr) {
    const result = []
    let leftIndex=0,rightIndex=0
    const leftLength = leftArr.length
    const rightLength = rightArr.length
    while(leftIndex < leftLength && rightIndex < rightLength) {
      if(leftArr[leftIndex] <= rightArr[rightIndex]) {
        result.push(leftArr[leftIndex++])
      } else {
        count += (leftLength - leftIndex ) // 关键: 取逆序对的个数
        result.push(rightArr[rightIndex++])
      }
    } 
  
    while(leftIndex < leftLength) {
      result.push(leftArr[leftIndex++])
    }
  
    while(rightIndex < rightLength) {
      result.push(rightArr[rightIndex++])
    }
    return result
  }
  mergeSort(nums)
  return count
};

image.png

  • 分析:

    • 时间复杂度:同归并排序 O(nlogn)。
    • 空间复杂度:同归并排序 O(n)O(n),因为归并排序需要用到一个临时数组。

我最后换了很多种写法,想把时空再优化一下,发现都差不多,然后感觉这种是最好理解了。算了就这样吧~~~

相关文章
|
1月前
|
算法
Leetcode 初级算法 --- 数组篇
Leetcode 初级算法 --- 数组篇
38 0
|
1月前
|
自然语言处理 前端开发 JavaScript
🛠️ JavaScript数组操作指南:20个精通必备技巧🚀
本文详细介绍了 JavaScript 中的 20 个高效数组操作技巧,涵盖了从基本的添加、移除元素,到数组转换和去重等高级操作。强调了不可变性的重要性,提供了清晰的代码示例,帮助开发者编写更整洁和高效的代码。无论是新手还是经验丰富的开发者,这些技巧都将显著提升您的编码能力,使您在项目中更具竞争力。
27 2
|
1月前
|
JavaScript 前端开发 测试技术
JS都有哪些操作数组的方法
JS都有哪些操作数组的方法
25 3
|
1月前
|
JavaScript
js删除数组中已知下标的元素
js删除数组中已知下标的元素
37 4
|
1月前
|
缓存 JavaScript 前端开发
JavaScript中数组、对象等循环遍历的常用方法介绍(二)
JavaScript中数组、对象等循环遍历的常用方法介绍(二)
34 1
|
1月前
|
JavaScript 前端开发 Java
【javaScript数组,函数】的基础知识点
【javaScript数组,函数】的基础知识点
25 5
|
1月前
【LeetCode-每日一题】 删除排序数组中的重复项
【LeetCode-每日一题】 删除排序数组中的重复项
20 4
|
1月前
|
索引
Leetcode第三十三题(搜索旋转排序数组)
这篇文章介绍了解决LeetCode第33题“搜索旋转排序数组”的方法,该问题要求在旋转过的升序数组中找到给定目标值的索引,如果存在则返回索引,否则返回-1,文章提供了一个时间复杂度为O(logn)的二分搜索算法实现。
19 0
Leetcode第三十三题(搜索旋转排序数组)
|
1月前
|
JavaScript 前端开发 索引
探索JavaScript数组:基础
探索JavaScript数组:基础
19 3
|
1月前
|
JavaScript 前端开发 索引
JS 删除数组元素( 5种方法 )
JS 删除数组元素( 5种方法 )
43 1