壹 ❀ 引

又到了每日一道算法题的环节,今天做的题同样非常简单,题目来源leetcode27. 移除元素,题目描述如下:

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

示例 1:

给定 nums = [3,2,2,3], val = 3,

函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。

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

示例 2:

给定 nums = [0,1,2,2,3,0,4,2], val = 2,

函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。

注意这五个元素可为任意顺序。

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

同样,我先说说我的解题思路,再分享更优的做法。

贰 ❀ 解题思路

即便是未了解过算法的同学我想应该都能轻易做出,题目要求很明了,给定一个数组与一个目标值,删除数组中与目标值相同的元素,最终返回操作完的数组长度。

这里我首先想到的肯定是直接使用splice删除符合条件的元素,直接贴代码:

/**
* @param {number[]} nums
* @param {number} val
* @return {number}
*/
var removeElement = function (nums, val) {
var i = 0,
len = nums.length;
for (; i < len; i++) {
// 如果当前项与目标值相同,则删除这一样
if (nums[i] === val) {
nums.splice(i, 1);
i--;
};
};
return nums.length;
};

思路很简单,这里我们还是简单复习一下splice方法,splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目。它接受三个参数:

arrayObject.splice(index,howmany,item1,.....,itemX)

其中index表示你要操作的起点,代表数组索引;howmany表示操作的个数,比如我要删除2个,还是3个。而item1,.....,itemX表示删除之后你希望加入的新元素。

需要注意的是splice方法会直接改变原数组,并返回被删除的元素数组。

let arr = [0,1,2,3];
let arr_ = arr.splice(0,2,4,5);
console.log(arr,arr_);// [4,5,2,3] [0,1]

这段代码表示,从arr索引0处删除2个元素,也就是0,1,删除后再加入4,5,所以修改后的arr为[4,5,2,3],返回的删除元素组成新的数组[0,1]

为什么里面有个i--呢,这是因为splice操作会修改原数组,让我们删除一项后,数组的length已经发生了变化,还按照原本i++遍历,会造成遍历跳过一项的问题,i--的目的就是为了重置i。

关于删除数组某项后要i--的思路,我保持了2年,直到今天遇到这道算法题,我才被改变,来看一个更棒的写法:

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

为了方便理解,举个例子,比如我们要删除数组[2,1,2]中的所有2,按照我前面的写法。

第一次遍历遇到2,i此时为0,删除后数组变成[1,2],i自增变成1,很明显1没判断被跳过了,所以才需要i--,让i变成-1,于是第二次遍历i++又变成了0,这样就不会跳过1了。

有没有觉得i--i++非常多余呢,上面优化的写法就是解决了这个问题,如果进行了删除操作,我们让当前的i不自增不就好了,只有不满足是才自增比较下一位。直到这段代码,改变了我2年多以来的的编程思路...

那么到这里就结束了吗?并没有,题目描述结尾有这样话,剩下的元素可为任意顺序,你不需要考虑数组中超出新长度后面的元素。

说实话我都不明白它想表达什么,直到我看了别人针对这句话想出的解答思路才明白是怎么回事。比如数组[2,1,3,2]要删除2,你可以把数组变成[1,3,2,2]都算符合答案,意思就是我得到了数组[1,3],只是这个数组超出了长度多了两个2,题目也说了不考虑超出,那么针对这个思路再给出一个实现,实现灵感来自于leetcode用户灵魂画手

/**
* @param {number[]} nums
* @param {number} val
* @return {number}
*/
var removeElement = function(nums, val) {
let ans = nums.length;
for (let i = 0; i < ans;) {
// 只要当前元素与val相同,就与数组后面交换
if (nums[i] == val) {
[nums[i], nums[ans - 1]] = [nums[ans - 1], nums[i]];
// 注意这里递减有两个目的
// 1.第一是保证每次交换都会往前走一位,不然一直交换最后一位了
// 2.第二是模拟删除掉val后剩余的元素个数
ans--;
} else {
i++;
};
};
return ans;
};

这个思路注释其实已经说的很明白了,符合条件的元素我们把它往数组最后面丢,用个例子来模拟一下,比如数组[3,2,1,3],我们要求去掉3的长度。

第一次遍历,i为0,nums[0]与3比较由于符合,那么当前 i 的元素就和数组最后一位互换,此时数组变成了[3,2,1,3]

注意,由于你不知道换过来的最后一位是否符合条件,所以此时 i 并不能自增,而是让ans递减,作用注释也说了。

于是仍然是nums[0]和3比较,又符合条件,这时候就不是和最后一位互换,由于ans递减,所以是倒数第二位,于是数组变成了[1,2,3,3],注意此时ans又得递减,i不变。

继续遍历,还是nums[0]与3比较,不符合,所以i自增,于是nums[1]又与目标值比较,不符合条件,最终跳出了循环。

由于有2个符合条件的元素,所以ans本质上等于原数组长度4-2=2,最终返回了2。

老实说,不看这个答案,我确实想不到这个题目描述是这个意思....当然这个实现思路确实很巧妙,也感叹大佬的思路也是够清晰。

那么关于此题就分析到这了。

JS leetcode 移除元素 题解分析的更多相关文章

  1. LeetCode移除元素

    LeetCode 移除元素 题目描述 给你一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,并返回移除后数组的新长度. 不需要使用额外的数组空间,你必须仅使用 O(1) ...

  2. LeetCode~移除元素(简单)

    移除元素(简单) 1. 题目描述 给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使 ...

  3. 【数组】leetcode——移除元素

    编号:27. 移除元素 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度. 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 ...

  4. leetcode 移除元素

    给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成 ...

  5. 前端与算法 leetcode 27.移除元素

    目录 # 前端与算法 leetcode 27.移除元素 题目描述 概要 提示 解析 算法 @(目录) # 前端与算法 leetcode 27.移除元素 题目描述 27.移除元素 概要 题目本身其实挺简 ...

  6. 【JavaScript】Leetcode每日一题-移除元素

    [JavaScript]Leetcode每日一题-移除元素 [题目描述] 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度. 不要使用 ...

  7. 分析轮子(八)- List.java 各种遍历方式及遍历时移除元素的方法

    注:玩的是JDK1.7版本 1:先尝栗子,再分析,代码简单,注释清晰,可自玩一下 /** * @description:测试集合遍历和移除元素的方式 * @author:godtrue * @crea ...

  8. JS中对数组元素进行增删改移

    在js中对数组元素进行增删改移,简单总结了一下方法: 方法 说明 实例 push( ); 在原来数组中的元素最后面添加元素 arr.push("再见58"); unshift( ) ...

  9. Java实现 LeetCode 27 移除元素

    27. 移除元素 给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额 ...

  10. 每日一道 LeetCode (8):删除排序数组中的重复项和移除元素

    每天 3 分钟,走上算法的逆袭之路. 前文合集 每日一道 LeetCode 前文合集 代码仓库 GitHub: https://github.com/meteor1993/LeetCode Gitee ...

随机推荐

  1. Shell 脚本编程学习

    本文为博主原创,转载请注明出处: 目录: 1. shell 变量 2. 运算符 3. if 语句 4.for 循环 5.while 语句 6. case 语法 7.跳出循环:continue 与 br ...

  2. 基于Html+腾讯云播SDK开发的m3u8播放器

    周末业余时间在家无事,学习了一下腾讯的云播放sdk,并制作了一个小demo(m3u8播放器),该在线工具是基于腾讯的云播sdk开发的,云播sdk非常牛,可以支持多种播放格式. 预览地址 m3u8pla ...

  3. R语言—数据基础及练习

    ## 创建leadership数据框 manager <- c(1,2,3,4,5) date <-c("10/24/08","10/28/08", ...

  4. SD协议-时序

    1.SD Timing 时序主要体现在CMD和Response的时序 S - 起始位,一直为0 T - Transmitter,1表示CMD(发起端是Host),0表示Response(发起端是Car ...

  5. 【ThreadX-NetX】Azure RTOS NetX概述

    Azure RTOS NetX是工业级TCP / IP IPv4嵌入式网络堆栈,专门针对深度嵌入式,实时和IoT应用程序而设计.Azure RTOS NetX是Microsoft最初的IPv4网络堆栈 ...

  6. [转帖]linux按行读取 (while read line与for-loop)

    https://cloud.tencent.com/developer/article/1655435 在linux下一般用while read line与for循环按行读取文件.现有如下test.t ...

  7. [转帖]tidb之旅——tidb架构选择

    https://zhuanlan.zhihu.com/p/641650168 前言 从4月份开始利用tidb改造了我们公司bi系统.这个过程中,我感觉到了tidb的强大.也打算记录一下整个改造过程.我 ...

  8. [转帖]Jmeter中线程组和setUP线程组、tearDown线程组的区别

    JMETER: setUP线程组:在测试任务ThreadGroup 运行前先被运行.通常用在运行测试任务前,做初始化工作.例如建立数据库连接初始分化工作.用户登录 tearDown线程组:在测试任务线 ...

  9. [转帖]linux的硬链接和软连接的区别

    Linux中有两种链接文件: 1)软链接(符号链接symbol),等同于Windows中快捷方式 ln -s 源文件名 符号链接文件名,源文件名和符号链接文件名是主从关系,源被删了,符号链接也就失效了 ...

  10. Rsync的简单使用

    Rsync的简单使用 需求 一个运行很久的系统里面可能包含了非常多的垃圾文件. 但是又不可能随便删除, 很多垃圾可能有某些奇葩的用法. 有时候新建一个应用复制文件的话比较浪费磁盘和带宽. 所以这里简单 ...