0
点赞
收藏
分享

微信扫一扫

JavaScript算法16- 删除有序数组中的重复项(leetCode:26)

hwwjian 2022-05-01 阅读 49

删除有序数组中的重复项


文章目录

一、题目

给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。

由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。

将最终结果插入 nums 的前 k 个位置后返回 k

不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

示例

输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

二、题解

方式1(改变数组长度)

  • 遍历数组,判断当前元素是否等于下一个元素,如果等于,就直接删除当前元素
  • 由于重复的元素会直接被删除,所以这种方法会改变数组长度
/**
 * @param {number[]} nums
 * @return {number}
 */
var removeDuplicates = function(nums) {
    let i = 0
    while (nums[i+1] !== undefined) {
        if (nums[i] === nums[i + 1]) {
            nums.splice(i,1)
        } else {
            i++
        }
    }
    
    return nums.length
};

在这里插入图片描述
这种方法虽然理解起来很简单,但性能感人。。
因为频繁删除数组元素非常耗费性能,详细原因在文末

方式2(不改变数组长度)

来自力扣的解法~~
思路
采用快慢指针
数组是有序的,那么重复的元素一定会相邻。在同一个数组里面操作,把不重复的元素移到数组的左侧,最后取左侧的数组的值。
步骤

  • 比较 fastlow位置的元素是否相等。
    ○ 循环执行:
       如果相等,fast 后移 1 位
       如果不相等,将low前一位的值改为fastlow 后移1位,fast 后移 1 位

    ○ 循环结束:
       fast越界

  • 循环结束,返回新数组长度 low + 1

/**
 * @param {number[]} nums
 * @return {number}
 */
var removeDuplicates = function(nums) {
    // 判断边界
    if (nums && nums.length < 0) {
        return 0
    }
    var low = 0, fast = 1, n = nums.length;
    while (fast < n) {
        if (nums[fast] !== nums[low]) {
          nums[low + 1] = nums[fast]
            low++  
        } 
        fast++
    }
    return low + 1
};

在这里插入图片描述

三、拓展

为什么频繁删除数组元素,会很耗费性能呢?
参考自浅谈JS数组在内存中的效率问题

1、我们所熟知的JS数组的结构和其他语言数组结构类似,即物理内存是连续的,所以这也就导致了数组成员移动次数越少,其效率越高,一般数组会被分配到一段连续的内存中,像这样
在这里插入图片描述
其实我们的数组在定义的时候默认了它的长度,即当我们想要在数组中添加或删除元素的时候,就需要对它的长度做出改变。

2、我们看到的仅仅只是数组中的一个元素被删除,其实底层数组中,这个元素后面的所有成员都需要向前移动,当移动元素非常多时,性能就会很差


额外补充:非连续内存问题

  • 我们都知道JS数组是可以在同一数组中存储不同数据类型的数据的。
  • 所以就造成了JS的数组是否分配连续内存,是要看我们的数组成员类型
  • 当数组内成员为同一类,则为连续内存
  • 当数组成员存在数组,字符串,那么就会分配非连续的内存
  • 多个非连续内存会形成一个链表,当存储数据数量级庞大的时候,就会造成效率低下的问题。
举报

相关推荐

0 条评论