Problem: 27. 移除元素
[TOC]
思路
为什么要使用左右指针?
如何才能移除等于val的值呢?把数组看成左右两个部分,其中左边都是不等于val的元素,右边都是等于val的元素,其中左边不等于val的元素数量就是k,k=nums.length - 右边等于val元素的数量。所以我们可以考虑使用左右指针
关于指针的移动
右指针负责寻找不等于val的元素的位置,左指针负责找等于val的元素的位置,然后两个元素交换,等于val的元素就移动到了右边,不等于val值得元素移动到了左边。
//右指针的移动可以使用while循环来实现 (需要注意下标是否越界)
while ( r >= 0 && nums[r] == val) {
r--;
}
//指针也是同理
while (l < nums.length && nums[l] != val && l < r ) {
l++;
}
关于k的大小
从上述解释中,我们可以知道,右指针的移动条件(while循环成立的条件)是只有当指针指向的元素等于val的时候,右指针才会向左移动,所以就代表着右指针的移动步数就代表着等于val的元素个数,我们可以使用一个临时变量
temp来计数,所以不等于val的元素个数就是nums.length - temp。值得注意的是,当交换之后,有右指针指向的仍然是等于val,所以当进入下一轮循环的时候这个交换后元素仍然会参与的计数,所以不会漏算。
图解
nums = [3,2,2,3]的时候
<,
,
,
>
复杂度
- 时间复杂度:
- 空间复杂度:
Code
class Solution {
public int removeElement(int[] nums, int val) {
if (nums.length == 1) {
return nums[0] == val ? 0 : 1;
}
int l = 0;
int r = nums.length - 1;
int ans = 0;
while (l < r) {
while (r >= 0 && nums[r] == val) {
r--;
ans++;
}
while (l < nums.length && nums[l] != val && l < r) {
l++;
}
if (r >= 0 && l < nums.length) {
int tmp = nums[l];
nums[l] = nums[r];
nums[r] = tmp;
}
}
return nums.length - ans;
}
}