【LeetCode】【C++】27. 移除元素 && 80.删除有序数组中的重复项Ⅱ

27. 移除元素

题目描述

详见LeetCode 27. 移除元素。

这是一道特别水的题,但是我第一时间没有想到正确的解答思路。

题目描述可以简述为,给定数组nums和元素val,原地删除nums中等于val的元素,并返回nums中不等于val元素的个数。

思路

一开始我确实想到了要使用双指针来做,但是我错误的将第二个指针设置到了nums的尾部,想要将等于val的元素直接和尾部的元素进行交换,这个思路有一个很大的问题在于,尾部的元素也可能等于val。

正确的双指针思路是,设置两个双指针,均从头开始对nums进行遍历,记作left和right。

如果nums[right] != val,意味着可以令nums[left] = nums[right],并将两个指针同时右移,否则只移动right指针。

最后left的值就是nums中不等于val的个数。

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

80.删除有序数组中的重复项Ⅱ

题目描述

详见leetcode原题目。

与这道题相似的是26. 删除有序数组中的重复项,这两道题与27. 移除元素类似,都涉及到原地对数组进行操作,都可以使用双指针算法来解决。

这道题目可以简单描述为,给定一个单调不减的数组,请原地删除数组当中的元素,使得重复的元素不超过两个,并返回最终数组的长度。

思路

自己还是太菜了,菜就要多练,参考了LeetCode的题解才想明白。

这道题仍然使用双指针算法来求解,但是不需要插旗来检查当前保留的元素是否超过两个。

需要注意的是对题目的性质进行仔细考察,仔细观察后可以发现,当前仅当当前位置ii-2的元素不相同时,才需要对该位置的元素进行保留操作,这也一定程度上利用了数组的有序性。

因此可以设置两个指针,分别是慢指针slow和快指针fast,使用慢指针slow来对数组当中的元素进行移动,使用快指针fast来对整个数组进行检查。

将这两个指针均初始化为2,如果nums[slow - 2] != nums[fast],说明此时要对数组当中的元素进行移动,即令nums[slow++] = nums[fast]

上述语句看似非常简单,它为什么是合理的呢?考虑nums[slow - 1],如果它与nums[slow - 2]是相等的,注意题目给定的条件,至多保留两个相同的元素,我们无需对它进行操作。只有当nums[slow - 2]nums[fast]不相等的时候,才需要将fast指针处的元素移动到slow指针处。

举个例子,假设有数组[1, 1, 2, 2, 2, 3, 3, 3, 3, 3],初始化的slow和fast都是2,即指向数组的第三个位置。初始化为2的原因是不需要考虑0和1两个位置的元素,而这必然是满足题意的,可以保留。对于fast == 2这个位置,nums[slow - 2]的值是1,与2不等,可以将fast位置的元素移动到slow。此时fast继续移动,移动到下标为3的位置时,nums[slow-2]的值仍然是1,与2不相等,仍然可以将fast位置的元素移动到slow。注意此时slow的值为4,因为保留了两个值为2的元素,slow此时指向的是下一个可能要将元素移动过来的位置。

然而,继续移动fast可以发现,当fast移动到下标为4的位置时,nums[slow-2]的值是2,此时fast和slow - 2指向的元素相等了,由于新数组当中的元素重复的次数不能超过2,所以此时不能将fast位置的元素移动到slow。

继续移动fast至下标为5的位置,此时fast位置的元素为3,slow-2位置的元素为2,slow-1位置的元素也是2,可以将fast位置的元素移动到slow。

代码如下:

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int n = nums.size();
        if(n <= 2) {
            return n;
        }
        int slow = 2, fast = 2;
        while(fast < n) {
            if(nums[slow - 2] != nums[fast]) {
                nums[slow ++] = nums[fast];
            }
            fast ++;
        }
        return slow;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值