「LeetCode」26.删除有序数组中的重复项

306 阅读2分钟

「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战」。

题目描述🌍

给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致

由于在某些语言中不能改变数组的长度,所以必须将结果放在数组 nums 的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。

将最终结果插入 nums 的前 k 个位置后返回 k

不要使用额外的空间,你必须在 原地 修改输入数组并在使用 O(1)O(1) 额外空间的条件下完成。

判题标准:

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

int[] nums = [...]; // 输入数组
int[] expectedNums = [...]; // 长度正确的期望答案

int k = removeDuplicates(nums); // 调用

assert k == expectedNums.length;
for (int i = 0; i < k; i++) {
    assert nums[i] == expectedNums[i];
}

如果所有断言都通过,那么您的题解将被通过。

示例 1

输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

示例 2

输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。

提示

  • 00 <= nums.length <= 31043 * 10^4
  • 104-10^4 <= nums[i] <= 10410^4
  • nums 已按升序排列

双指针法🚧

解题思路

经典的双指针问题。

设一个指针 i (快指针)对数组进行遍历,而另一个指针 j (慢指针)则指向有效数组的末位。

只有当 i 指向的值与 j 指向的值不同的时候(即元素不重复),才将 i 指向的值赋给 j 指向的下一位置。

代码

Java

class Solution {
    public int removeDuplicates(int[] nums) {
        int n = nums.length;
        int j = 0;
        for (int i = 0; i < n; i++) {
            if (nums[j] != nums[i])
                nums[++j] = nums[i];
        }
        return j + 1;
    }
}

C++

class Solution {
public:
    int removeDuplicates(vector<int> &nums) {
        int pre = 0;
        int length = nums.size();
        for (int i = 1; i < length; ++i) {
            if (nums[pre] != nums[i])
                nums[++pre] = nums[i];
        }
        return pre + 1;
    }
};

时间复杂度:O(n)O(n)

空间复杂度:O(1)O(1)

知识点🌓

什么是「原地算法」?

简单来说,原地算法(或算法原地工作)就是指算法所需的辅助空间是常量

Wikipedia 维基百科

计算机科学中,一个原地算法(in-place algorithm,也称“就地算法”)是基本上不需要借助额外的数据结构就能对输入的数据进行变换的算法。不过,分配少量空间给部分辅助变量是被允许的。算法执行过程中,输入的数据往往会被输出结果覆盖。原地算法只能通过替换或交换元素的方式来修改原始的输入。

不满足“原地”原则的算法也被称为非原地(not-in-place)算法或异地(out-of-place)算法。

通用解法

为了让解法更具有一般性,我们将原问题的「最多保留 1 位」修改为「最多保留 k 位」。

该通用解法源于「宫水三叶」,三叶姐 yyds!

⭐接下来以本题要求 k=1 为例,给出各语言版本

Java

class Solution {
    public int removeDuplicates(int[] nums) {
        // 假设 k=1, 即本题要求
        return process(nums, 1);
    }

    int process(int[] nums, int k) {
        int idx = 0; 
        for (int x : nums) {
            if (idx < k || nums[idx - k] != x)
                nums[idx++] = x;
        }
        return idx;
    }
}

C++

class Solution {
public:
    int removeDuplicates(vector<int> &nums) {
        return process(nums, 1);
    }

    int process(vector<int> &nums, int k) {
        int idx = 0;
        for (auto x: nums) {
            if (idx < k || nums[idx - k] != x) {
                nums[idx++] = x;
            }
        }
        return idx;
    }
};

最后🌅

该篇文章为 「LeetCode」 系列的 No.7 篇,在这个系列文章中:

  • 尽量给出多种解题思路
  • 提供题解的多语言代码实现
  • 记录该题涉及的知识点

👨‍💻争取做到 LeetCode 每日 1 题,所有的题解/代码均收录于 「LeetCode」 仓库,欢迎随时加入我们的刷题小分队!