持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第23天,点击查看活动详情
前言
题目来源
题目介绍
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
// nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝
int len = removeElement(nums, val);
// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}
题目分析
根据题目意思和例子示意,我们需要把一个已知数组移除一些元素(等于val的元素),返回一个新数组的长度。因此我们可以先遍历数组,判断元素是否等于val,如果不等于就从下标0开始重新赋值元素。
题目验证
class Solution {
public int removeElement(int[] nums, int val) {
int n=nums.length;
//定义一个表示下标的变量
int newNum=0;
for(int i=0;i<n;i++){
if(nums[i]!=val){
nums[newNum++]=nums[i];
}
}
return newNum;
}
}
定义一个0开始的表示下标的变量,遍历数组,如果元素满足条件,那么赋值当前元素值给数组[下标],最后返回我们的下标变量,即所求的数组的长度。验证如下
相对来说,这个代码量还是比较简单的。
官方答案验证
class Solution {
public int removeElement(int[] nums, int val) {
int n = nums.length;
int left = 0;
for (int right = 0; right < n; right++) {
if (nums[right] != val) {
nums[left] = nums[right];
left++;
}
}
return left;
}
}
这个基本一摸一样,根据题目要求把输出的数组直接写在输入数组上。可以使用双指针:右指针 right 指向当前将要处理的元素,左指针left 指向下一个将要赋值的位置。
还有一种优化解法
class Solution {
public int removeElement(int[] nums, int val) {
int left = 0;
int right = nums.length;
while (left < right) {
if (nums[left] == val) {
nums[left] = nums[right - 1];
right--;
} else {
left++;
}
}
return left;
}
}
这种叫双指针解法,如果左指针left 指向的元素等于 val,此时将右指针 right 指向的元素复制到左指针 left 的位置,然后右指针right 左移一位。如果赋值过来的元素恰好也等于 val,可以继续把右指针right 指向的元素的值赋值过来(左指针left 指向的等于 val 的元素的位置继续被覆盖),直到左指针指向的元素的值不等于 val 为止。
当左指针 left 和右指针 right 重合的时候,左右指针遍历完数组中所有的元素。执行结果如下,确实有优化。
总结
这道题一开始我也不太明白,返回长度就行了吗,按照题目意思和示例看起来是这样的,不用额外增加删除操作代码。