壹 ❀ 引

又到了每日一道算法题的环节,今天做的题同样非常简单,题目来源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. 12_前K个高频元素

    前K个高频元素 给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素.你可以按 任意顺序 返回答案.347.力扣题目链接 示例 1: 输入: nums = [1,1,1, ...

  2. 机器学习-线性分类-支持向量机SVM-SMO算法-14

    目录 1. SVM算法总结 2. SMO算法 1. SVM算法总结 选择 核函数 以及对应的 超参数 为什么要选择核函数? 升维 将线性问题不可分问题 升维后转化成 线性可分的问题 核函数 有那些? ...

  3. 机器学习-线性分类-SVM支持向量机算法-12

    目录 1. 铺垫 感知器算法模型 2. SVM 算法思想 3. 硬分割SVM总结 支持向量机(Support Vector Machine, SVM)本身是一个二元分类算法,是对感知器算法模型的一种扩 ...

  4. 以太网链路连接 和 ISIS/OSPF等路由协议关系

    转载请注明出处: 以太网链路连接和ISIS/OSPF协议之间存在关联和区别 关联: 以太网链路连接是指通过以太网物理媒介(如电缆)将网络设备进行连接,使它们可以交换数据. ISIS(Intermedi ...

  5. springBoot 整合 hikari

    Hikari是一款非常强大,高效,并且号称"史上最快连接池".并且在springboot2.0之后,采用的默认数据库连接池就是Hikari.不需要引入依赖,已经在SpringBoo ...

  6. ApplicationContextAware 的理解和应用

    当我们在项目中获取某一个spring bean时,可以定义一个类,实现ApplicationContextAware  该接口,该接口可以加载获取到所有的 spring bean. package c ...

  7. [转帖]Nginx 安全优化

    目录 前言 1.使用 SSL/TLS 证书 2.使用安全密钥交换机制 3.禁用旧的 SSL/TLS 协议 4.禁用 SSL/TLS 弱密码套件 5.禁用不需要的 HTTP 方法 6.防止缓冲区溢出攻击 ...

  8. [转帖]Linux下非oracle用户如何使用系统认证方式登陆数据

    https://www.cnblogs.com/kerrycode/p/17772866.html Linux系统中,DBA一般使用oracle用户登陆/访问Linux操作系统,然后使用sqlplus ...

  9. [转帖]k8s之PV、PVC、StorageClass详解

    https://zhuanlan.zhihu.com/p/128552232 导读 上一篇写了共享存储的概述以及一个简单的案例演示.这一篇就写一下PV和PVC. PV是对底层网络共享存储的抽象,将共享 ...

  10. [转帖]Linux—CPU核数、上下文切换介绍及pidstat等命令详解

    https://www.jianshu.com/p/0ae0c1153c34 关注:CodingTechWork,一起学习进步. 引言 并发编程   并发编程的目的是为了改善串行程序执行慢问题,但是, ...