「这是我参与2022首次更文挑战的第23天,活动详情查看:2022首次更文挑战」。
描述
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
做题
因为我们需要在原来的数组上进行操作,所以不可避免地为了交换元素而使用双指针的方法来做这道题。
思路
一个指针从头开始,另一个指针从尾开始。
每次移动头指针,当遇到和 val 相同的元素,就把尾指针的元素放到当前头指针的位置。
接着往前移动尾指针,但不要移动头指针,因为我们还需要判断一下新赋值的头指针上的元素是否和 val 相同。
二次判断不相同才移动头指针,也就是说只有不和 val 相同时才移动头指针。
当判断相同时,就再把尾指针上的元素放到头指针上。
举例演示
输入: nums = [3,2,2,3], val = 3
nums = [3,2,2,3];l = 0,r = 3 or nums.length - 1;
第一趟循环:因为nums[l] == 3; 所以要把 nums[r] 赋值给 nums[l],以及 r--;,不要移动 l。
nums = [3,2,2,3];l = 0,r = 2;
第二趟循环:nums[l] == 3;,所以要继续把 nums[r] 赋值给 nums[l],以及 r--;,不要移动 l。
nums = [2,2,2,3];l = 0,r = 1;
第三趟循环:nums[l] != 3;,所以 l++。
nums = [2,2,2,3];l = 1,r = 1;
第四趟循环:这次还是需要循环一次,虽然这时可以直接返回了,但是我们实际上是没有判断 nums[1] 的,而且这次 l++ 可以让 l 等于返回数组的长度。此时,nums[l] != 3;,所以 l++。
return l;
运行的代码
public int removeElement(int[] nums, int val) {
// 头指针 l,尾指针 r。
int l = 0,r = nums.length -1;
while(l <= r){
int num = nums[l];
if(num == val){
// 当前的元素等于 val,把 r 指针指向的元素放到当前的 l指针的位置上
nums[l] = nums[r];
r--;
}else{
// 不相等时,移到下一位
l++;
}
}
return l;
}
踩过的坑
一开始我想着这么做:
-
头指针依然是从头开始,遇到和 val 相同的元素时,就停下来。
-
然后,尾指针往前,遇到和 val 相同的元素就跳过,直到遇到和 val 不相同的元素,再放到头指针上。
代码如下:
public int removeElement(int[] nums, int val) {
int l = 0,r = nums.length -1;
while(l <= r){
int num = nums[l];
if(num == val){
// 当前的元素等于 val,把 r 指针指向的元素放到当前的 l指针的位置上
while(r > 0 && nums[r] == val){
r--;
}
nums[l] = nums[r];
r--;
}
l++;
}
return l ;
}
but,这种做法的返回长度会有问题,加个 if 判断一下吧,那还不如用之前的做法,所以就不了了之了。
最后
今天就到这里了。
这里是程序员徐小白,【每日算法】是我新开的一个专栏,在这里主要记录我学习算法的日常,也希望我能够坚持每日学习算法,不知道这样的文章风格您是否喜欢,不要吝啬您免费的赞,您的点赞、收藏以及评论都是我下班后坚持更文的动力。