"删除排序数组中的重复项" 普通解和性能优化解

2019/10/9 posted in  leetcode

饭后小憩

官方地址:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/submissions/

问题描述

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

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

示例 1:

给定数组 nums = [1,1,2],

函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。

你不需要考虑数组中超出新长度后面的元素。

基本事实

比较容易想到的就是 相邻的元素进行比较,然后删除相同的相邻元素即可,重复这个过程直到数组末尾

另一种不容易想到的就是 把不重复的元素重新覆盖到元素数组中(不能使用额外数组,满足不使用额外的数组空间)

算法实现

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int size = nums.size();
        if (size == 0) {
            return 0;
        }
        if (size == 1) {
            return 1;
        }
        int dup = nums[0];
        for (int i = 1; i < size; i ++) {
            if (dup == nums[i]) {
                nums.erase(nums.begin() + i, nums.begin() + i + 1);
                i --;
                size --;
            } else {
                dup = nums[i];
            }
        }
        return size;
    }
};

可以看到虽然通过了这个测试,但是耗时太多了

算法实现-性能优化

上面的性能问题除出在移除重复元素的代码nums.erase(nums.begin() + i, nums.begin() + i + 1)上,下面换一种思路,就是不直接删除这个元素,而是把不重复的元素重新覆盖到nums数组中(从前往后覆盖),以此来提升执行效率(不重复元素个数 <= 数组长度)

注意:和数组末尾元素交换后,就应该跳过数组末尾元素的遍历了

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

可以看到执行速度得到了近10倍的提升,这个优化还是非常划算的。

一些注意的点

覆盖解法时,需要单独的计数器count来对不重复的元素进行计数

参考资料

  1. https://leetcode-cn.com/submissions/detail/32431084/