• JS leetcode 删除排序数组中的重复项 题解分析


    壹 ❀ 引

    一日一题,今天的题目来自于leetcode26. 删除排序数组中的重复项,其实在之前我们已经做了一道类似的题目,可参考JS leetcode 移除元素 题解分析,关于本题描述如下:

    给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

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

    示例 1:

    给定数组 nums = [1,1,2], 
    
    函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 
    

    你不需要考虑数组中超出新长度后面的元素
    示例 2:

    给定 nums = [0,0,1,1,1,2,2,3,3,4],
    
    函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。
    

    你不需要考虑数组中超出新长度后面的元素

    我们先来简单分析题目,再给出解题思路。

    贰 ❀ 解题思路

    经过leetcode算法题移除元素的教育,这次解题得额外抓住两个重点:

    第一,题目真正的要求是获取不重复元素的长度,所以即使不删除重复元素也是允许的。

    第二,不需要考虑数组中超出新长度后的元素,这句话的意思其实已经暗示,我们可以将不重复的元素集中在数组前面,后面的重复元素可以不管,比如

    [1,2,2,3] => [1,2,3,2] 返回3,因为不重复的元素为 1,2,3
    

    当然,我们可以先站在删除重复元素的角度来思考这个问题,这对于前端开发者来说更容易接受,直接上代码:

    /**
     * @param {number[]} nums
     * @return {number}
     */
    var removeDuplicates = function (nums) {
        for (var i = 0; i < nums.length;) {
            if (nums.indexOf(nums[i]) !== i) {
                nums.splice(i, 1);
            } else {
                i++;
            };
        };
        return nums.length;
    };
    

    思路很简单,因为indexOf获取的都是每个元素第一次出现的问题,所以只要当前元素的i不是第一次出现,那就说明是重复元素,利用splice删除执行元素即可。

    而站在不删除元素的角度,这就得利用双指针进行元素覆盖,我们先上代码,再解释原理:

    /**
     * @param {number[]} nums
     * @return {number}
     */
    var removeDuplicates = function (nums) {
        if(nums.length === 0){
            return 0;
        };
        var s = 0, //慢指针,每赋值一次,慢指针往右移动一位
            f = 1, //快指针,只要重复就往右移动一位
            len = nums.length;
        for (; f < len; f++) {
            if (nums[s] !== nums[f]) {
                nums[s + 1] = nums[f];
                s++;
            };
        };
        return s + 1;
    };
    

    我们以[1,1,2,3]为例,注意,题目已经说了数组为已排序数组,所以相同元素必定相邻。

    我们指定2个指针,慢指针s(slow)与快指针f(fast),慢指针主要负责当元素不同时进行赋值,快指针主要负责数组遍历,对每个元素进行比较。

    说到底,就是每次比较完成之后,只要这个元素没重复,就把这个元素通过赋值的形式,依次排在s指针索引的后面;若比较相同就啥都不干,直接让快指针继续往后移动。

    我们通过图解,来模拟[1,1,2,3]的赋值过程:

    可以看到,一开始由于s为0,f为1,进行了第一次比较,如果相同,s作为起点元素保持不变,f作为快指针继续寻找下个比较目标;

    而只要s与f的元素不同,则将f的元素复制到s的后一位,以此类推,由于s的索引是0,经过几次复制自增几次,最后获取的长度需要额外加1,大致上就是这个思路。

    我最开始也是绕了半天,但是通过图解,真是感叹双指针的微妙之处。

    当然,双指针代码处的if操作其实也可以改写成如下形式,思路是一样的,不过我还是认为上述写法好理解一点,先赋值,s再移动:

    if (nums[s] !== nums[f]) {
        s++;
        nums[s] = nums[f];
    };
    

    那么关于本题的分析就到这里了。

  • 相关阅读:
    nput keyup 500ms 延时输入 事件处理
    browser-sync默认地址如何转成127.0.0.1
    overflow:scroll-css知识备忘
    圆角的css样式
    支付宝开发
    C#代码与javaScript函数的相互调用
    高性能web开发 如何加载JS,JS应该放在什么位置?
    Makefile自动生成头文件依赖
    一步步教你如何写Makefile
    (一):U-BOOT启动分析--概述
  • 原文地址:https://www.cnblogs.com/echolun/p/13045504.html
Copyright © 2020-2023  润新知