class Solution {
public int removeElement(int[] nums, int val) {
if(nums==null || nums.length==0)
return 0;
int len = 0;
for(int i = 0;i<nums.length;i++){
if(nums[i]==val)
len++;
else
nums[i-len]=nums[i];
}
return nums.length-len;
}
}
这题还是简单,我一开始还思考迪化想用队列存储待删除元素的坐标,现在看来完全是多虑了。
时间复杂度
O
(
n
)
O(n)
O(n),空间复杂度
O
(
1
)
O(1)
O(1)。
官方解答的思路和我是一致的。
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
\textit{right}
right 指向当前将要处理的元素,左指针
left
\textit{left}
left 指向下一个将要赋值的位置。
如果右指针指向的元素不等于
val
\textit{val}
val,它一定是输出数组的一个元素,我们就将右指针指向的元素复制到左指针位置,然后将左右指针同时右移;
如果右指针指向的元素等于
val
\textit{val}
val,它不能在输出数组里,此时左指针不动,右指针右移一位。
整个过程保持不变的性质是:区间
[
0
,
left
)
[0,\textit{left})
[0,left) 中的元素都不等于
val
\textit{val}
val。当左右指针遍历完输入数组以后,
left
\textit{left}
left 的值就是输出数组的长度。
宫水三叶的答案的代码更加精简,但是可能是赋值操作过于频繁了,导致占用了更高的内存。力扣26的拓展也是他写的。
class Solution {
public int removeElement(int[] nums, int val) {
int idx = 0;
for (int x : nums) {
if (x != val) nums[idx++] = x;
}
return idx;
}
}
设定变量 idx,指向待插入位置。idx 初始值为 0
然后从题目的「要求/保留逻辑」出发,来决定当遍历到任意元素 x 时,应该做何种决策:
- 如果当前元素 x 与移除元素 val 相同,那么跳过该元素。
- 如果当前元素 x 与移除元素 val 不同,那么我们将其放到下标 idx 的位置,并让 idx 自增右移。
最终得到的 idx 即是答案。