【LeetCode26.删除有序数组中的重复项】——双指针法

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

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

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

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

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

示例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 。不需要考虑数组中超出新长度后面的元素。

提示:

  • 1 <= nums.length <= 3 * 104
  • -104 <= nums[i] <= 104
  • nums 已按 升序 排列

思路:

本题也是经典的双指针算法题,对于一个数组来说,删除一个元素是比较复杂的,每次删除元素后,若要保留原有的顺序,则需要将后面的元素一个个先前“挪”一格位置,这样操作的话,算法的时间复杂度是较高的。

所以就有了双指针法,分为快慢指针法以及左右指针法,能够实现在一个for循环下完成两个for循环的工作。

而关于本题,有个很重要的条件就是,所给定的数组是有序的,是按升序排序的,这就大大简化了算法的难度。

而关于数组删除元素相关的题目,我们可以避免在中间删除元素,而是可以想办法把要删除的元素换到最后去,最后一起删除。

两遍循环:

我们可以利用一种最朴素的方法,即暴力地使用两遍for循环进行求解,外层的for循环用于查找重复的元素,当寻找到重复的元素后,利用内层的for循环,将数组集体向前移动一位。

 //暴力解法
    int removeDuplicates(vector<int>& nums) {
        int size = nums.size();
        for (int i = 0; i < size-1; i++) {
            if (nums[i] == nums[i+1]) { // 发现重复的元素
                for (int j = i + 1; j < size; j++) { //将数组集体向前移动一位
                    nums[j - 1] = nums[j];
                }
                i--; // 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
                size--; // 记录此时的数组大小
            }
        }
        return size;
    }

本题使用暴力解法在LeetCode上是会超时的。

这里面有个细节问题,就是外层for循环的结束条件是i<size-1而不是size,若是size的话会因为之前数组元素集体向前移动,导致最后一次遍历中,必定出现ums[i] == nums[i+1],这样就会导致多删除一个元素。由于最后一个元素在前一轮循环中,已经比较过了,所以循环到size-1即可。

快慢双指针:

设置快慢双指针,分别指向数组,完成各自任务。

快指针:不停止,勇往直前,寻找重复元素

慢指针:用于记录更新新数组的下标位置

  int removeDuplicates2(vector<int>& nums) {
        int slow = 0; //初始化慢指针
        for (int fast = 0; fast < nums.size()-1; fast++) { //快指针对整个数组进行遍历,寻找重复值
            if (nums[fast]!= nums[fast+1]) { //若不为目标值,更新慢指针,并赋值给新数组
                nums[slow] = nums[fast];
                slow++;
            }
        }
        //最后一位另外作讨论
        nums[slow] = nums[nums.size()-1];
        slow++;
        return slow;
    }

这里我用的是将遍历到的数组元素与它后面一位的元素作比较,若是两元素相等,则不更新slow指针,若是和后一位不等,说明是不重复的新元素,更新slow指针。

这么做有一个弊端:数组的最后一位没有后一位元素。所以最后一位要单独拿出来考虑,由于没有后一位元素,数组的最后一位必定是不重复的新元素,可以直接加入到slow新数组中,这里我是将循环结束条件设为fast < nums.size()-1,然后再循环结束后,单独将最后一位添加至slow对应的新数组中。

当然,为了很好地规避这个问题,我们可以使用后一位与前一位作比较的方法,这个时候,数组为空的情况要拿出来单独讨论:

//来自leetcode官方题解 
int removeDuplicates(vector<int>& nums) {
        int n = nums.size();
        if (n == 0) {
            return 0;
        }
        int fast = 1, slow = 1;
        while (fast < n) {
            if (nums[fast] != nums[fast - 1]) {
                nums[slow] = nums[fast];
                ++slow;
            }
            ++fast;
        }
        return slow;
}

进一步优化版:

经过进一步思考发现,只需将快慢指针所对应的值进行比较即可。

  //最终优化版
     int removeDuplicates4(vector<int>& nums) {
         int n = nums.size();
         if (n == 0) return 0;
         int slow = 0;
         for (int fast = 0; fast < n; fast++) {
             if (nums[slow] != nums[fast]) {
                 nums[++slow] = nums[fast];
             }
         }
         return slow + 1;
     }

后续也会坚持更新我的LeetCode刷题笔记,欢迎大家关注我,一起学习。
如果这篇文章对你有帮助,或者你喜欢这篇题解,可以给我点个赞哦。
CSDN同步更新,欢迎关注我的博客:一粒蛋TT的博客_CSDN博客-LeetCode学习笔记,HTML+CSS+JS,数据结构领域博主

往期回顾:
LeetCode27.移除元素

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,492评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,048评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,927评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,293评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,309评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,024评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,638评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,546评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,073评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,188评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,321评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,998评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,678评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,186评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,303评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,663评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,330评论 2 358

推荐阅读更多精彩内容