LeetCode82刪除排序鏈表中的重復元素 II

文章目錄

  • 刪除排序鏈表中的重復元素 II
    • 題目描述
      • 示例
    • 核心思想
    • 最優雅解法
    • 算法步驟詳解
      • 示例1演示:[1,2,3,3,4,4,5]
    • 關鍵理解點
      • 1. 虛擬頭節點的作用
      • 2. 重復檢測邏輯
      • 3. 完全刪除重復節點
    • 邊界情況處理
      • 情況1:空鏈表
      • 情況2:單節點
      • 情況3:全部重復
      • 情況4:頭節點重復
    • 復雜度分析
    • 常見錯誤
      • 1. 忘記虛擬頭節點
      • 2. 重復刪除不完全
      • 3. 指針更新錯誤
    • 總結

刪除排序鏈表中的重復元素 II

題目描述

給定一個已排序的鏈表的頭 head,刪除原始鏈表中所有重復數字的節點,只留下不同的數字。

示例

示例1:
輸入:head = [1,2,3,3,4,4,5]
輸出:[1,2,5]
解釋:3和4都出現了重復,所以要全部刪除示例2:
輸入:head = [1,1,1,2,3]  
輸出:[2,3]
解釋:1出現了重復,所以要全部刪除

核心思想

與刪除重復元素I不同,這里要求完全刪除重復的節點,而不是保留一個。

關鍵技巧:

  1. 虛擬頭節點:因為頭節點也可能被刪除
  2. 雙指針prev 指向最后一個確定保留的節點,curr 用于遍歷
  3. 跳過重復:發現重復時,跳過所有相同值的節點

最優雅解法

class ListNode {int val;ListNode next;ListNode() {}ListNode(int val) { this.val = val; }ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}class Solution {public ListNode deleteDuplicates(ListNode head) {// 創建虛擬頭節點,簡化邊界處理ListNode dummy = new ListNode(0);dummy.next = head;// prev:指向最后一個確定保留的節點// curr:用于遍歷的當前節點ListNode prev = dummy;ListNode curr = head;while (curr != null) {// 檢查是否有重復:curr和curr.next值相同if (curr.next != null && curr.val == curr.next.val) {int duplicateVal = curr.val;// 跳過所有值為duplicateVal的節點while (curr != null && curr.val == duplicateVal) {curr = curr.next;}// 連接prev和curr,刪除所有重復節點prev.next = curr;} else {// 當前節點無重復,prev前進prev = curr;curr = curr.next;}}return dummy.next;}
}

算法步驟詳解

示例1演示:[1,2,3,3,4,4,5]

初始狀態:
dummy → 1 → 2 → 3 → 3 → 4 → 4 → 5 → null↑      ↑
prev   curr步驟1:檢查curr(1)和curr.next(2)
1 ≠ 2,無重復
prev = curr = 1, curr = 2dummy → 1 → 2 → 3 → 3 → 4 → 4 → 5 → null↑   ↑prev curr步驟2:檢查curr(2)和curr.next(3)  
2 ≠ 3,無重復
prev = curr = 2, curr = 3dummy → 1 → 2 → 3 → 3 → 4 → 4 → 5 → null↑   ↑prev curr步驟3:檢查curr(3)和curr.next(3)
3 = 3,發現重復!
duplicateVal = 3
跳過所有值為3的節點:curr = 4dummy → 1 → 2 → 3 → 3 → 4 → 4 → 5 → null↑           ↑prev        curr連接:prev.next = curr
dummy → 1 → 2 ─────────→ 4 → 4 → 5 → null↑           ↑prev        curr步驟4:檢查curr(4)和curr.next(4)
4 = 4,發現重復!
duplicateVal = 4  
跳過所有值為4的節點:curr = 5dummy → 1 → 2 ─────────→ 5 → null↑           ↑prev        curr連接:prev.next = curr
dummy → 1 → 2 ────────→ 5 → null↑          ↑prev       curr步驟5:檢查curr(5)和curr.next(null)
curr.next = null,無重復
prev = curr = 5, curr = null最終結果:[1,2,5]

關鍵理解點

1. 虛擬頭節點的作用

ListNode dummy = new ListNode(0);
dummy.next = head;
  • 簡化邊界處理,避免特殊判斷頭節點
  • 保證 prev 始終有效

2. 重復檢測邏輯

if (curr.next != null && curr.val == curr.next.val) {// 發現重復
}
  • 通過比較相鄰節點檢測重復
  • 由于鏈表已排序,重復元素必然相鄰

3. 完全刪除重復節點

int duplicateVal = curr.val;
while (curr != null && curr.val == duplicateVal) {curr = curr.next;  // 跳過所有重復值
}
prev.next = curr;  // 連接到下一個不重復的節點
  • 記錄重復值,跳過所有相同值的節點
  • 直接連接 prev 和第一個不重復的節點

邊界情況處理

情況1:空鏈表

head = null
return dummy.next = null ?

情況2:單節點

head = [1]
curr.next = null,不進入重復檢測
return [1] ?

情況3:全部重復

head = [1,1,1]
全部刪除,prev.next = null
return [] ?

情況4:頭節點重復

head = [1,1,2,3]
虛擬頭節點確保正確處理
return [2,3] ?

復雜度分析

  • 時間復雜度:O(n)
    • 每個節點最多被訪問2次(檢測+跳過)
  • 空間復雜度:O(1)
    • 只使用了常數個指針變量

常見錯誤

1. 忘記虛擬頭節點

// 錯誤:頭節點重復時處理復雜
ListNode prev = null;
if (head.val == head.next.val) {// 復雜的頭節點刪除邏輯...
}

2. 重復刪除不完全

// 錯誤:只刪除一個重復節點
if (curr.val == curr.next.val) {curr.next = curr.next.next;  // 只刪除一個
}

3. 指針更新錯誤

// 錯誤:在刪除重復節點后錯誤更新prev
prev.next = curr;
prev = curr;  // 錯誤!curr指向被刪除的節點

總結

這個算法的精髓在于:

  1. 虛擬頭節點 簡化邊界處理
  2. 雙指針技巧 保持連接關系
  3. 完全跳過 所有重復值的節點
  4. 正確連接 prev和下一個有效節點

這是處理鏈表刪除問題的經典模式,特別適用于需要刪除多個連續節點的場景!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/921102.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/921102.shtml
英文地址,請注明出處:http://en.pswp.cn/news/921102.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

藍橋杯算法之基礎知識(6)

目錄 Ⅰ.os操作 Ⅱ.時間庫(很重要) Ⅲ.基本單位換算(ms,min,h的單位換算) Ⅳ.時間戳 Ⅴ.文件讀取 Ⅵ.堆 Ⅶ.math操作 Ⅷ.range()方法單獨使用 Ⅸ.python 的異常輸出 Ⅹ.for…

多架構/系統圖,搞懂:期貨賬戶體系,太通透了!

Hi,圍爐喝茶聊產品的新老朋友好!上周和大家聊了國內6大期貨交易所清算交收,感興趣的話煩請戳藍色鏈接去學習,就當為下面學習作知識鋪墊,更重要是溫故知新,并保持知識連貫性。另外圍爐特意整理了與賬戶相關的文章,如下所示: “保證金被扣”拆解期貨交易所:清算交收體系…

python-對圖片中的頭像進行摳圖

要實現對圖片中人臉或頭像進行摳圖,可以使用 Python 的 人臉檢測 和 掩碼生成裁剪工具。這里提供幾種實現方法,用于檢測圖片中的人臉區域并實現裁剪效果: 方案 1: 使用 OpenCV 和 Haar級聯檢測人臉并裁剪 步驟 1: 安裝依賴 安裝 OpenCV 和其他…

OpenLayers常用控件 -- 章節一:地圖縮放控件詳解教程

前言在Web地圖開發中,縮放控件是用戶與地圖交互最基本也是最重要的功能之一。OpenLayers作為功能強大的開源地圖庫,提供了多種縮放控件來滿足不同的交互需求。本文將結合一個完整的Vue.js示例,詳細介紹OpenLayers中三種主要的縮放控件&#x…

拓撲學:數學領域的魅力之鑰

拓撲學:數學領域的魅力之鑰 關鍵詞:拓撲學、連續變形、同胚、流形、代數拓撲、點集拓撲、應用數學 摘要:本文深入探討拓撲學這一現代數學的重要分支,從其基本概念到高級理論,從純數學研究到實際應用。我們將從點集拓撲的基礎開始,逐步深入到代數拓撲和微分拓撲的復雜世界…

iOS 上架 uni-app 流程全解析,從打包到發布的完整實踐

uni-app 作為跨平臺開發框架,憑借“一套代碼,多端運行”的特性,已經成為不少團隊和個人開發者的首選。 然而,很多開發者在 iOS 應用上架環節,常常遇到流程復雜、工具分散、審核繁瑣等問題。 本文將以 iOS 上架 uni-app…

go 語言map是線程不安全的如何處理

在 Go 語言中,map確實是線程不安全的。當多個 goroutine 并發讀寫同一個 map 時,會導致 ?race condition?(競態條件),可能引發程序崩潰或數據不一致。以下是解決方案:一、基本方案:使用互斥鎖…

落地頁測試case(Android視角)

落地頁按鈕或者adjust的鏈接的跳轉功能和測試case(Android視角) 如果沒有安裝應用,跳轉到應用商店的應用下載界面如果已經安裝應用,跳轉到應用內,再從應用內跳轉到相應的頁面如果落地頁是在window打開,點擊…

前端自動化打包服務器無法安裝高版本 Node.js v22 問題解決

問題:安裝高版本 node,報錯。具體表現 當執行 node -v 命令時,系統提示多個 GLIBC_xxx 版本未找到,比如 GLIBCXX_3.4.21、GLIBC_2.27 等,這些是 node 程序運行所依賴的 Glibc 庫的特定版本符號,當前系統安裝…

shell腳本第七階段--三劍客之awk

學習目標熟悉awk的命令行模式基本語法結構熟悉awk的相關內部變量熟悉awk常用的打印函數print能夠在awk中匹配正則表達式打印相關的行一、awk介紹awk是一種編程語言,主要用于在linux/unix下對文本和數據進行處理,是linux/unix下的一個工具。數據可以來自標…

Unity 的游戲循環機制

Unity 的游戲循環機制在 Unity 中,游戲的運行是基于幀的。每一幀都遵循固定的執行順序:處理輸入執行游戲邏輯 (包括 Update、FixedUpdate 和協程)渲染場景顯示幀為什么 GameTime.time 在同一幀內不變GameTime.time 是只讀屬性:它返回的是當前…

算法題(198):數字三角形

審題: 本題需要我們找到數字三角形中的最大路徑總值,并輸出 思路: 方法一:動態規劃 由于本題的路徑權值是路徑上每一個值累加起來,問題具有階段重復性,所以我們嘗試使用動態規劃解決此問題 (1&a…

變頻器實習DAY42 VF與IF電機啟動方式

目錄變頻器實習DAY42一、工作內容1.1 OF229程序重新燒錄和測試二、學習內容2.1 VF與IF電機啟動方式1. VF(Voltage Frequency)啟動電機2. IF(Current Frequency)啟動電機總結附學習參考網址歡迎大家有問題評論交流 (* ^ ω ^)變頻器…

B樣條曲線,已知曲線上的某個點到起點的距離,確定這個點的參數u的值的方法

B樣條曲線:已知弧長 L 求參數 u 的方法1. B樣條曲線定義B樣條曲線由以下要素定義:控制點:P?, P?, P?, ..., P?節點向量( Knot Vector ):U [u?, u?, ..., u?]曲線次數:k(例如…

云計算學習100天-第44天-部署郵件服務器

目錄 電子郵件通信——郵件服務器 基本功能 郵件通信的尋址 案例 網絡架構 配置server服務器 電子郵件通信——郵件服務器 基本功能 為用戶提供電子郵箱存儲空間 處理用戶發出的郵件——傳遞給收件服務器 處理用戶收到的郵件——投遞到郵箱 郵件通信的尋址 根據收件…

計算機視覺(七):膨脹操作

在計算機視覺中,膨脹是一種基本的形態學操作,主要用于處理和分析圖像的形狀。它通過“膨脹”或“放大”圖像中的前景對象來增加其尺寸或連接斷開的區域。 膨脹操作的工作原理類似于卷積,但使用的是結構元素 (structuring element)&#xff0c…

playwright+python UI自動化測試中實現圖片顏色和像素對比

def compare_image(expect_path, actual_path, output_path, color_diff_threshold10.0,max_diff_pixels100):# 讀取圖片img1 cv2.imread(expect_path)img2 cv2.imread(actual_path)if img1.shape ! img2.shape:img2 cv2.resize(img2, (img1.shape[1], img1.shape))# ------…

企業級AI應用,Dify集成RAGFlow知識庫保姆教程

第一部分:RAGFlow 端配置 在 Dify 能夠調用之前,確保 RAGFlow 已經就緒并提供了可訪問的 API。 步驟 1: 確保 RAGFlow 正常運行 具體可以參考:https://blog.csdn.net/qq_35354529/article/details/151149191?spm1001.2014.3001.5502 注意啟動…

daily notes[9]

文章目錄ubuntu notereferencesubuntu note Ubuntu can be written into a stick that boot ubuntu.the stick have the following effects. to install or upgrade Ubuntu include on macto experience the Ubuntu desktop without any actual operation in your OS.Disk Ut…

Java中 String、StringBuilder 和 StringBuffer 的區別?

在Java中,String、StringBuilder 和 StringBuffer 都用于處理字符串,但它們在可變性、線程安全性和性能上有顯著區別。以下是它們的對比:1. String不可變性(Immutable)String 對象一旦創建,內容不可修改。任…