【快慢指针】LeetCode - 80. 删除排序数组中的重复项 II

本文介绍了如何使用双指针技巧在已排序数组中删除最多两次重复项,通过对比当前元素和前两个元素避免O(N^2)复杂度,达到线性时间复杂度O(n)。实例解析与代码实现清晰易懂。

题目描述

题目链接
在这里插入图片描述
在这里插入图片描述

解法

方法一:删除多余的重复项

由于输入数组已经排序,所以重复项都显示在旁边。题目要求在原地修改数组,最简单的方法就是删除多余的重复项。对于数组中的每个数字,若出现 2 个以上的重复项,就将多余的重复项从数组列表中删除。

这里的删除是指将待删除项后面的全部数据向前挪一格,显然,这种算法的复杂度是O(N^2)

方法二:覆盖多余的重复项

这需要两个指针,即双指针,或者说是快慢指针也无所谓,因为快慢指针的含义是两个移动速度或者别的方面没有联系的指针。

到此,快慢指针的两个常见用法我都已经接触到了。一个是判断有无环,实质是判断有无重复项;另一个是这里学习的删除重复项
(所以遇到有关重复项的就想快慢指针 ???)

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int index = 0;
        for(int i : nums)
        {
            if(index < 2 || i != nums[index - 2])
             nums[index++] = i;
        }
        return index;
    }
};

思路我不会组织语言,就举个例子吧,简洁明了

举例: 1 1 1 1 2 3 3

  • 第一个指针是遍历数组的 i,为了简便,我把这里的 i 设置成nums[i],也就是说它不是遍历指针(或者说下标),而是挨着的一个个数组中的数
  • 另一个指针是比 i 要更往前走的 index,用话术说 index 是要覆盖上去的元素的位置,不理解没关系,往下看它的功能也就明白了
  • 首先 i = 1(也就是num[0]),index = 0
  • 因为题目要求至多重复2次,那么 index < 2 时不需要考虑,跟着遍历数组的 i 走就行了,此时 nums = [1, 1] , i = 1(第二个1), index ++ 之后现在是2
  • 再次进入for循环, index >=2 时就要小心多余重复了,允许的情况是 i != nums[index - 2],表示再往后是不重复的数。这里用 index - 2 是因为题目要求是至多重复2次,所以跟往前2个的数作比较(注意,index 是一直在自增的),如果要求不允许重复,这里就应该是 Index - 1 了(LeetCode - 26. 删除排序数组中的重复项

这种算法的时间复杂度是O(n),因为是需要遍历数组一遍。

终于差不多说完了,其实理解了之后不是很难,但就是很难表述清楚我感觉(或许是我功力不够吧 orz)

LeetCode第26题“删除排序数组中的重复项”有以下几种解法: #### 解法一:使用额外数组 ```java public class Solution { public int removeDuplicates(int[] nums) { // 如果数组 nums[] 的长度为 0,则数组不包含任何元素,因此返回 0 if(nums==null||nums.length==0){ return 0; } // 定义存放非重复项数组 int b[] = new int[nums.length]; b[0] = nums[0]; // 因为b[0] 已经确定,所以 数量k初始值为1,index下标 初始值也为1 int k = 1; int index = 1; for(int i = 1; i < nums.length; i++){ // 如果一个数和它前一个不相等,就认为是非重复项 if(nums[i] != nums[i - 1]){ // 将非重复项赋值给b[] b[index] = nums[i]; k++; // 数量加一 index++; // 下标加一 } } // b.length==k,将b数组重新赋值给nums的前k个元素 for(int i = 0; i < k; i++){ nums[i] = b[i]; } return k; } } ``` 此解法先判断数组是否为空或长度为0,若为真则返回0。接着创建一个新数组来存放非重复元素,遍历原数组,将非重复元素存入新数组,并记录非重复元素的数量和下标。最后将新数组的前k个元素复制回原数组,并返回k [^1]。 #### 解法二:快慢指针 ```java class Solution { public int removeDuplicates(int[] nums) { int i = 0; for(int j = i + 1; j < nums.length; ++j){ // 找到了不与nums[i]的重复的值,则将不重复的值赋值放在i的后面一位,同时i的下标后移一位,开始下一个数的重复判断。 if(nums[j] != nums[i]){ nums[++i] = nums[j]; } } return i + 1; } } ``` 该解法利用快慢指针,慢指针`i`用于记录非重复元素的位置,快指针`j`用于遍历数组。当`nums[j]`与`nums[i]`不相等时,将`nums[j]`赋值给`nums[++i]`,最后返回`i + 1` [^2]。 #### 解法三:另一种快慢指针写法 ```java class Solution { public int removeDuplicates(int[] nums) { if (nums == null || nums.length == 0) return 0; int p = 0, q = 1; while (q < nums.length) { if (nums[p] != nums[q]) { nums[p + 1] = nums[q]; p++; } q++; } return p + 1; } } ``` 此解法同样使用快慢指针,`p`指针指向当前的非重复元素位置,`q`指针用于遍历数组。当`nums[p]`与`nums[q]`不相等时,将`nums[q]`赋值给`nums[p + 1]`,并将`p`指针后移一位,最后返回`p + 1` [^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值