【每日算法】力扣27. 移除元素

124 阅读2分钟

「这是我参与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;
}

image.png

踩过的坑

一开始我想着这么做:

  1. 头指针依然是从头开始,遇到和 val 相同的元素时,就停下来。

  2. 然后,尾指针往前,遇到和 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 判断一下吧,那还不如用之前的做法,所以就不了了之了。

最后

今天就到这里了。

这里是程序员徐小白,【每日算法】是我新开的一个专栏,在这里主要记录我学习算法的日常,也希望我能够坚持每日学习算法,不知道这样的文章风格您是否喜欢,不要吝啬您免费的赞,您的点赞、收藏以及评论都是我下班后坚持更文的动力。