27.移除元素


题目:两数之和

给你一个数组nums和一个值val,你需要原地移除所有数值等于val的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

  • 示例 1:
输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。
  • 示例 2:
输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。
  • 提示:
0 <= nums.length <= 100
0 <= nums[i] <= 50
0 <= val <= 100

思路1

我们可以保留两个指针ij,其中i是慢指针,j是快指针。当nums[j]与给定的值相等时,递增j以跳过该元素。只要nums[j] ≠ val,我们就把nums[j]赋值到nums[i]并同时递增两个索引。重复这一过程,直到j到达数组的末尾,该数组的新长度为i

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

代码

public int removeElement(int[] nums, int val) { // 总时间复杂度O(n)
    if (nums.length == 0) {
        return 0;
    }
    // 慢指针
    int i = 0;
    // 快指针
    int j = 0;
    while (j <= nums.length - 1) { // 时间复杂度O(n)
        if (nums[j] != val) {
            nums[i] = nums[j];
            i++;
        }
        j++;
    }
    return i;
}

思路2

考虑数组包含很少的要删除的元素的情况。例如,nums = {1, 2, 3, 5, 4},val = 4,之前的算法会对前四个元素做不必要的赋值操作。另一个例子是nums = {4, 1, 2, 3, 5},val = 4,似乎没有必要将{1,2,3,5}这几个元素左移一步,因为问题描述中提到元素的顺序可以更改。
可以考虑遇到nums[i] = val时,将当前元素与最后一个元素进行交换,并释放最后一个元素。这实际上使数组的大小减少了1。

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

代码

public int removeElement(int[] nums, int val) { // 总时间复杂度O(n)
    if (nums.length == 0) {
        return 0;
    }
    int i = 0;
    int length = nums.length;
    while (i < length) { // 时间复杂度O(n)
        // nums[left]等于目标值的时候,nums[left]位置存放最后一个元素,把最后一个元素丢弃掉
        if (nums[i] == val) {
            nums[i] = nums[length - 1];
            length--;
        } else {
            i++;
        }
    }
    return length;
}

文章作者: cxyexe
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 cxyexe !
  目录