刷题系列之27. 移除元素

90 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第23天,点击查看活动详情

前言

题目来源

leetcode.cn/leetbook/re…

题目介绍

给你一个数组 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开始的表示下标的变量,遍历数组,如果元素满足条件,那么赋值当前元素值给数组[下标],最后返回我们的下标变量,即所求的数组的长度。验证如下

image.png

image.png

相对来说,这个代码量还是比较简单的。

官方答案验证

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 重合的时候,左右指针遍历完数组中所有的元素。执行结果如下,确实有优化。

image.png

总结

这道题一开始我也不太明白,返回长度就行了吗,按照题目意思和示例看起来是这样的,不用额外增加删除操作代码。