移除元素

给你一个数组 nums 和一个值 val,你需求 原地 移除一切数值等于 val 的元素,并回来移除后数组的新长度

不要运用额定的数组空间,你有必要仅运用 O(1) 额定空间并 原地 修正输入数组

元素的次序能够改变。你不需求考虑数组中超出新长度后面的元素。

双指针

关于要求原地完结移除,咱们能够运用双指针的方法完结。

首要咱们界说 lr两个指针,r指针指向当时需求处理的元素,l指针则指向要被覆盖的元素,即新数组的尾部。遍历数组,当r指针指向的元素与val不相等时,则将r指针指向的元素移动到l指针指向的数组下标,并将lr两个指针向后移动一位;否则只移动r指针。

最终,l指针指向的下标便是新数组的尾部,依据题意,直接放回l 即可。


```cpp
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int n = nums.size(), l = 0, r = 0;
        for(; r < n; r  ) {
            if(nums[r] != val) {
                nums[l] = nums[r];
                l  ;
            }
        }
        return l;
    }
};

进一步优化,假如咱们要移除的元素刚好在数组的头部,此刻需求把每一个元素都左移一位,这样比较费时。依据题意,新数组的元素的排序是能够改更改的。这样咱们就能够直接将数组中的最终一个元素移动到数组头部,如此也是满意题目的要求。

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int l = 0, r = nums.size();
        while(l < r) {
            if(nums[l] == val) {
                nums[l] = nums[r - 1];
                r--;
            } else {
                l  ;
            }
        }
        return l;
    }
};

删去有序数组中的重复项

给你一个 非严格递增排列 的数组 nums,请你 原地 删去重复呈现的元素,使每个元素 只呈现一次,回来删去后数组的新长度。元素的 相对次序 应该保持 一致。然后回来 nums 中仅有元素的个数。

考虑 nums 的仅有元素的数量为 k,你需求做以下事情保证你的题解能够被经过:

  • 更改数组 nums,使 nums 的前 k 个元素包含仅有元素,并按照它们开始在 nums 中呈现的次序排列。nums 的其余元素与 nums 的大小不重要。
  • 回来 k

判题标准:

系统会用下面的代码来测试你的题解:

int[] nums = [...]; // 输入数组
int[] expectedNums = [...]; // 长度正确的期望答案
int k = removeDuplicates(nums); // 调用
assert k == expectedNums.length;
for (int i = 0; i < k; i  ) {
    assert nums[i] == expectedNums[i];
}

假如一切断语都经过,那么您的题解将被 经过

双指针

这题相同能够运用双指针完结,由于题意说明数组是有序的,即重复的元素一定是相邻的。

咱们界说 lr两个指针,r指针指向当时需求处理的元素,l指针则指向要被覆盖的元素,即新数组的尾部。遍历数组,当r指针指向的元素与l指针指向元素不相等时,则将r指针指向的元素移动到l指针指向的数组下一位,并将lr两个指针向后移动一位;否则只移动r指针。最终l 1即是新数组的长度。

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int n = nums.size();
        if(n == 0) return 0;
        int l = 0, r = 0;
        for(; r < n; r  ) {
            if(nums[l] != nums[r]) {
                nums[  l] = nums[r];
            }
        }
        return l   1;
    }
};

思考

  1. 若给出的数组不是有序的呢?该怎么完结

删去有序数组中的重复项 II

给你一个有序数组 nums,请你 原地 删去重复呈现的元素,使得呈现次数超越两次的元素只呈现两次,回来删去后数组的新长度。

不要运用额定的数组空间,你有必要在 原地 修正输入数组 并在运用 O(1) 额定空间的条件下完结。

说明:

为什么回来数值是整数,但输出的答案是数组呢?

请注意,输入数组是以**「引用」**方法传递的,这意味着在函数里修正输入数组关于调用者是可见的。

你能够想象内部操作如下:

// **nums** 是以“引用”方法传递的。也便是说,不对实参做任何拷贝
int len = removeDuplicates(nums);
// 在函数里修正输入数组关于调用者是可见的。
// 依据你的函数回来的长度, 它会打印出数组中 **该长度范围内** 的一切元素。
for (int i = 0; i < len; i  ) {
  print(nums[i]);
}

双指针

跟上一题一样,不同的是相同的元素能够保存两位。

相同能够运用双指针完结,只需求略微改动一下。

首要,数组长度在2及2以下的都能够满意条件。关于超越2的,咱们界说lr两个指针,r指针指向当时需求处理的元素,l指针则指向要被覆盖的元素,即新数组的尾部。遍历数组,当r指针指向的元素与l-2指针指向的元素不相等时(刚好满意保存两位相同数的要求),则将r指针指向的元素移动到l指针指向的数组下标,并将lr两个指针向后移动一位;否则只移动r指针。最终,新数组的长度为l,依据题意放回l即可。

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int n = nums.size();
        if (n <= 2) return n;
        int l = 2, r = 2;
        for(; r < n; r  ) {
            if(nums[l - 2] != nums[r]) {
                nums[l  ] = nums[r];
            }
        }
        return l;
    }
};