【LeetCode26.刪除有序數(shù)組中的重復(fù)項】——雙指針法

26.刪除有序數(shù)組中的重復(fù)項

給你一個 升序排列 的數(shù)組 nums 璧榄,請你 原地 刪除重復(fù)出現(xiàn)的元素庞溜,使每個元素 只出現(xiàn)一次 ,返回刪除后數(shù)組的新長度医增。元素的 相對順序 應(yīng)該保持 一致 蜀漆。

由于在某些語言中不能改變數(shù)組的長度谅河,所以必須將結(jié)果放在數(shù)組nums的第一部分。更規(guī)范地說确丢,如果在刪除重復(fù)項之后有 k 個元素旧蛾,那么 nums 的前 k 個元素應(yīng)該保存最終結(jié)果。

將最終結(jié)果插入 nums 的前 k 個位置后返回 k 蠕嫁。

不要使用額外的空間,你必須在 原地 修改輸入數(shù)組 并在使用 O(1) 額外空間的條件下完成毯盈。

示例1:

輸入:nums = [1,1,2]
輸出:2, nums = [1,2,_]
解釋:函數(shù)應(yīng)該返回新的長度 2 剃毒,并且原數(shù)組 nums 的前兩個元素被修改為 1, 2 。不需要考慮數(shù)組中超出新長度后面的元素搂赋。

示例2:

輸入:nums = [0,0,1,1,1,2,2,3,3,4]
輸出:5, nums = [0,1,2,3,4]
解釋:函數(shù)應(yīng)該返回新的長度 5 赘阀, 并且原數(shù)組 nums 的前五個元素被修改為 0, 1, 2, 3, 4 。不需要考慮數(shù)組中超出新長度后面的元素脑奠。

提示:

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

思路:

本題也是經(jīng)典的雙指針算法題基公,對于一個數(shù)組來說,刪除一個元素是比較復(fù)雜的宋欺,每次刪除元素后轰豆,若要保留原有的順序胰伍,則需要將后面的元素一個個先前“挪”一格位置,這樣操作的話酸休,算法的時間復(fù)雜度是較高的骂租。

所以就有了雙指針法,分為快慢指針法以及左右指針法斑司,能夠?qū)崿F(xiàn)在一個for循環(huán)下完成兩個for循環(huán)的工作渗饮。

而關(guān)于本題,有個很重要的條件就是宿刮,所給定的數(shù)組是有序的互站,是按升序排序的,這就大大簡化了算法的難度僵缺。

而關(guān)于數(shù)組刪除元素相關(guān)的題目胡桃,我們可以避免在中間刪除元素,而是可以想辦法把要刪除的元素換到最后去谤饭,最后一起刪除标捺。

兩遍循環(huán):

我們可以利用一種最樸素的方法,即暴力地使用兩遍for循環(huán)進行求解揉抵,外層的for循環(huán)用于查找重復(fù)的元素亡容,當尋找到重復(fù)的元素后,利用內(nèi)層的for循環(huán)冤今,將數(shù)組集體向前移動一位闺兢。

 //暴力解法
    int removeDuplicates(vector<int>& nums) {
        int size = nums.size();
        for (int i = 0; i < size-1; i++) {
            if (nums[i] == nums[i+1]) { // 發(fā)現(xiàn)重復(fù)的元素
                for (int j = i + 1; j < size; j++) { //將數(shù)組集體向前移動一位
                    nums[j - 1] = nums[j];
                }
                i--; // 因為下標i以后的數(shù)值都向前移動了一位,所以i也向前移動一位
                size--; // 記錄此時的數(shù)組大小
            }
        }
        return size;
    }

本題使用暴力解法在LeetCode上是會超時的戏罢。

這里面有個細節(jié)問題屋谭,就是外層for循環(huán)的結(jié)束條件是i<size-1而不是size,若是size的話會因為之前數(shù)組元素集體向前移動龟糕,導(dǎo)致最后一次遍歷中桐磁,必定出現(xiàn)ums[i] == nums[i+1],這樣就會導(dǎo)致多刪除一個元素讲岁。由于最后一個元素在前一輪循環(huán)中我擂,已經(jīng)比較過了,所以循環(huán)到size-1即可缓艳。

快慢雙指針:

設(shè)置快慢雙指針校摩,分別指向數(shù)組,完成各自任務(wù)阶淘。

快指針:不停止衙吩,勇往直前,尋找重復(fù)元素

慢指針:用于記錄更新新數(shù)組的下標位置

  int removeDuplicates2(vector<int>& nums) {
        int slow = 0; //初始化慢指針
        for (int fast = 0; fast < nums.size()-1; fast++) { //快指針對整個數(shù)組進行遍歷溪窒,尋找重復(fù)值
            if (nums[fast]!= nums[fast+1]) { //若不為目標值坤塞,更新慢指針冯勉,并賦值給新數(shù)組
                nums[slow] = nums[fast];
                slow++;
            }
        }
        //最后一位另外作討論
        nums[slow] = nums[nums.size()-1];
        slow++;
        return slow;
    }

這里我用的是將遍歷到的數(shù)組元素與它后面一位的元素作比較,若是兩元素相等尺锚,則不更新slow指針珠闰,若是和后一位不等,說明是不重復(fù)的新元素瘫辩,更新slow指針伏嗜。

這么做有一個弊端:數(shù)組的最后一位沒有后一位元素。所以最后一位要單獨拿出來考慮伐厌,由于沒有后一位元素承绸,數(shù)組的最后一位必定是不重復(fù)的新元素,可以直接加入到slow新數(shù)組中挣轨,這里我是將循環(huán)結(jié)束條件設(shè)為fast < nums.size()-1,然后再循環(huán)結(jié)束后军熏,單獨將最后一位添加至slow對應(yīng)的新數(shù)組中。

當然卷扮,為了很好地規(guī)避這個問題荡澎,我們可以使用后一位與前一位作比較的方法,這個時候晤锹,數(shù)組為空的情況要拿出來單獨討論:

//來自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;
}

進一步優(yōu)化版:

經(jīng)過進一步思考發(fā)現(xiàn)摩幔,只需將快慢指針所對應(yīng)的值進行比較即可。

  //最終優(yōu)化版
     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;
     }

后續(xù)也會堅持更新我的LeetCode刷題筆記鞭铆,歡迎大家關(guān)注我或衡,一起學習。
如果這篇文章對你有幫助车遂,或者你喜歡這篇題解封断,可以給我點個贊哦。
CSDN同步更新舶担,歡迎關(guān)注我的博客:一粒蛋TT的博客_CSDN博客-LeetCode學習筆記,HTML+CSS+JS,數(shù)據(jù)結(jié)構(gòu)領(lǐng)域博主

往期回顧:
LeetCode27.移除元素

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末坡疼,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子衣陶,更是在濱河造成了極大的恐慌回梧,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件祖搓,死亡現(xiàn)場離奇詭異,居然都是意外死亡湖苞,警方通過查閱死者的電腦和手機拯欧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來财骨,“玉大人镐作,你說我怎么就攤上這事藏姐。” “怎么了该贾?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵羔杨,是天一觀的道長。 經(jīng)常有香客問我杨蛋,道長兜材,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任逞力,我火速辦了婚禮曙寡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘寇荧。我一直安慰自己举庶,他們只是感情好,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布揩抡。 她就那樣靜靜地躺著户侥,像睡著了一般。 火紅的嫁衣襯著肌膚如雪峦嗤。 梳的紋絲不亂的頭發(fā)上蕊唐,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音寻仗,去河邊找鬼刃泌。 笑死,一個胖子當著我的面吹牛署尤,可吹牛的內(nèi)容都是我干的耙替。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼曹体,長吁一口氣:“原來是場噩夢啊……” “哼俗扇!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起箕别,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤铜幽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后串稀,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體除抛,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年母截,在試婚紗的時候發(fā)現(xiàn)自己被綠了到忽。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖喘漏,靈堂內(nèi)的尸體忽然破棺而出护蝶,到底是詐尸還是另有隱情,我是刑警寧澤翩迈,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布持灰,位于F島的核電站,受9級特大地震影響负饲,放射性物質(zhì)發(fā)生泄漏堤魁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一绽族、第九天 我趴在偏房一處隱蔽的房頂上張望姨涡。 院中可真熱鬧,春花似錦吧慢、人聲如沸涛漂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽匈仗。三九已至,卻和暖如春逢慌,著一層夾襖步出監(jiān)牢的瞬間悠轩,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工攻泼, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留火架,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓忙菠,卻偏偏與公主長得像何鸡,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子牛欢,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容