讓我們一起啃演算法----刪除排序連結串列中的重複元素 II

三斤和他的喵發表於2020-05-20

刪除排序連結串列中的重複元素 II(Remove-Duplicates-From-Sorted-List-II)

題幹如下:

給定一個排序連結串列,刪除所有含有重複數字的節點,只保留原始連結串列中 沒有重複出現 的數字。
示例 1:
  輸入: 1->2->3->3->4->4->5
  輸出: 1->2->5
示例 2:
  輸入: 1->1->1->2->3
  輸出: 2->3

這題是上一篇 讓我們一起啃演算法—-刪除排序連結串列中的重複元素 的進階版。在上一篇中,我們刪掉了重複的其他元素,僅保留一個元素,例如: 1 -> 2 -> 2 -> 3 變成 1 -> 2 -> 3。這題,則需要將僅保留的一個元素也刪掉,例如: 1 -> 2 -> 2 -> 3 變成 1 -> 3

解題思路

借上一篇的思路,我們需要在 current 指標基礎上再多準備一個前置指標 pre 和一個有效值指標 really。really 指標始終指向有效連結串列的尾部,pre 指標指向 current 的前置節點,因為我們需要比較當前節點 current 的值是否和前置節點、後置節點的值相等,在單向連結串列中,後置節點很容易獲取,即 current.next,但是前置節點不能很容易獲取到,需要用 pre 記錄。

初始化:由於需要一個前置節點,當 current 為連結串列的頭節點 head 時前置節點其實是不存在的,為了方便後續的邏輯,我們需要設定一個初始節點 origin,使 pre、really 指向 origin,current 指向 head。

判斷 current 的 val 與 current.next 的 val 和 pre 的 val 是否相等,相等的話,則 pre 指向 current, current 指向 current.next,如果不相等,則 really.next 指向 current,really 指向 current,同時 pre 指向 current,current 指向 current.next,大致思路如上。但是這裡有個注意事項:

按照上面的邏輯,pre 指向 current 後,需要將 pre.next 置為空,例如連結串列為: 1 —-> 2 —-> 2,如果不把 節點1 與 節點2 的連線斷開,後續返回的 origin.Next 連結串列結構為: 1 —-> 2 —-> 2 仔細體會一下!

流程圖如下:

程式碼實現

GO語言實現

func deleteDuplicates(head *ListNode) *ListNode {
    origin := &ListNode{Val:0}
    current := head
    pre := origin
    really := origin
    for current != nil {
        // 因為新引入了一個初始節點,防止和原始連結串列的第一個節點衝突,比如第一個節點剛好 Val 也為 0
        // 那麼單純 current.Val != pre.Val 判斷是不夠的,需要加入 pre == origin 這個判斷
        if (pre == origin || current.Val != pre.Val) && (current.Next == nil || current.Val != current.Next.Val) {
            really.Next = current
            really = current

        }

        pre = current
        current = current.Next

        // 這裡需要將 pre 和 current 之間的連線斷開,例如連結串列為: 1---->2---->2,
        // 如果不把 節點1 與 節點2 的連線斷開,後續返回的 origin.Next 連結串列結構為: 1---->2---->2 仔細體會一下!
        pre.Next = nil
    }
    return origin.Next
}

總結

每天進步一點點,加油!
演算法教程專案,每天更新一題,點個 star 支援一下呀
github.com/wx-satellite/learning-a...

本作品採用《CC 協議》,轉載必須註明作者和本文連結

三斤

相關文章