盲猜封面会被吞 o(一︿一+)o(不吞我就发评论区)
今天要写的是力扣上非常经典的双指针题目,原地移除元素,先看题目:
![](https://img-blog.csdnimg.cn/img_convert/bd1a5360f5b2cb38faff8921c4eb02f6.png)
![](https://img-blog.csdnimg.cn/img_convert/8807b0d92ff0ffb34212e725e4b11d35.png)
法一,最简单直接的思路,其实就是左右指针各遍历一遍数组,将非val从第一个往后赋值,这样还能保证元素相对顺序不变.不过多解释,代码相对简单:
class Solution {
public static int removeElement(int[] nums, int val) {
int left = 0;
for(int i = 0;i<nums.length;i++){
if(nums[i] != val){
nums[left++]=nums[i]; //右指针的值不等于val时赋给左指针;
}
}
return left;
}
}
法二,其实我们可以使右指针去寻找非val,然后赋值给值为val的左指针,这种思路对于要移除的val相对少时,效率要比法一高一些,左指针从0开始向右移动,右指针从右向左,这样只需要遍历一次数组即可.
我这个思路看起来很好,但是实际上我写的时候很费劲,各种查漏补缺调bug,我还纳闷明明很简洁的思路就是会出现这么多bug.以下是我的代码:
class Solution {
public static int removeElement(int[] nums, int val) {
int left = 0,right = nums.length-1;
while(left <= right){
while(nums[left] != val&&left < right){
left++;
}
while(nums[right] == val&&left < right){
right--;
}
if(nums[left] != val&&left == right) //这里额外的两个if是为了处理一些实例情况
return left + 1; //造成代码冗余
if(nums[left] == val&&left == right)
return left;
nums[left++] = nums[right--]; //两个指针同时动,不是好选择
}
return left;
}
}
这段代码我写的并不满意,很不够简洁,我去看了一眼答案,和我相似的思路,却比我简洁许多,我仔细进行了比对,发现根本原因在于我让两个指针同时动,这样对循环过程控制的不够细,导致每一次大循环都走得很快,很容易出现细节问题,而如果一次只动一个指针,那么控制起来就会相对简单很多,而且这样也只需要遍历一次.以下是官方给的答案:
class Solution {
public static int removeElement(int[] nums, int val) {
int left = 0;
int right = nums.length-1;
while(left <= right){
if(nums[left]==val){
nums[left] = nums[right--];
}else{
left++;
}
}
return left;
}
}
官方答案实际上忽略了右指针的值直接赋给左指针,因为这么写可以直接检查给过来的值是否为val,如果是val则left不动,继续原地赋值.
好了,今天的题解就分享到这里,这道题还是非常经典的,建议大家多做几次,并且用多种思路解决,有助于我们加强对指针思想的理解与运用.