壹 ❀ 引

又到了每日一道算法题的环节,今天做的题同样非常简单,题目来源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. nohup 与 >/dev/null 与 2>&1 作用与区别

    转载请注明出处: 在 Linux 中,>/dev/null 和 2>&1 是两个常用的重定向操作,它们用于控制命令的输出和错误信息.而且这两个参数经常 与 nohup 命令一起使用 ...

  2. 图的遍历(DFS和BFS)

    声明:图片及内容基于https://www.bilibili.com/video/BV1rp4y1Q72r?from=articleDetail 图的遍历 深度优先遍历(DFS) DFS核心是递归和栈 ...

  3. 【TouchGFX】Callback

    回调函数模板定义 单参数回调函数模板 实现回调函数接口: 实现合法性检查接口: 实现执行接口: 按键触发回调实现 定义回调数据结构对象 使用回调数据结构构造函数 执行接口实现 整个切换机制的管理主体对 ...

  4. Spring——静态/动态代理模式

    代理模式 代理模式: 静态代理 动态代理 学习aop之前,要先了解代理模式 静态代理 抽象角色:一般使用接口或者抽象类来实现 真实角色:被代理的角色 代理角色:代理真实角色:代理真实角色后,一般会做一 ...

  5. SpringMVC07——Ajax

    Ajax AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML). AJAX 不是新的编程语言,而是一种使用现有标准的新方法. AJA ...

  6. Stress-ng 的简单学习

    背景 想研究一下国产和不同架构,不通型号CPU的算力 也作为后续生产交付的基线准备. 学习各种不同工具进行简要测试. 安装 git clone https://github.com/ColinIanK ...

  7. rel分支合并进入dev分支有冲突怎么处理?

    rel分支合并进入dev分支有冲突怎么处理? 切换到本地rel 拉取远端rel 切换本地dev 拉去远端dev git merge rel 会出现冲突 解决后 推送到远端就可以

  8. VUe2.0 和 Vue3.0 的生命周期作对比

    VUe2.0 和 Vue3.0 的生命周期作对比 beforeCreate -> 请使用 setup() created -> 请使用 setup() beforeMount -> ...

  9. 强化学习基础篇[2]:SARSA、Q-learning算法简介、应用举例、优缺点分析

    强化学习基础篇[2]:SARSA.Q-learning算法简介.应用举例.优缺点分析 1.SARSA SARSA(State-Action-Reward-State-Action)是一个学习马尔可夫决 ...

  10. 解决:VScode中 import 后出现no module的问题

    问题: ModuleNotFoundError: No module named 'xxx' 除去没有安装包的问题 这个问题还是挺难受的,pycharm和终端都可以运行,只有vscode报错 方法一: ...