題目
刪除鏈表中等於給定值 val 的所有節點。
示例:
輸入: 1->2->6->3->4->5->6, val = 6
輸出: 1->2->3->4->5
來源Leetcode: https://leetcode-cn.com/problems/remove-linked-list-elements/
分析
遇到這種經典的鏈表題的時候,我懵逼了,我不會。。。繞頭腦,稍微不注意就會繞進去了,就不知道指針指哪裏了。所以這題我要好好分析分析,好好記錄一下,來理解這種鏈表。
這個題目啊,要注意是刪除給定值的所有節點。注意到我加粗的地方了嗎?
我們知道刪除鏈表元素時候,只需要把前一個節點的Next指向當前節點的Next元素,從而就可以丟棄到當前要刪除的節點。所以我們要記錄上一個節點prev。
假如cur節點是要刪除的節點,那麼將prev.Next = cur.Next即可實現刪除。
但我們知道,刪除節點要注意如果刪除的是頭節點呢。我可以簡單的將head = head.Next,但如果有多個連續的呢?那麼我們可能要做一個while循環一直檢測,一直刪除。
這裏就有另外一種處理了,做一個僞頭,也就是哨兵節點。哨兵節點指向頭節點,這樣刪除頭節點就和刪除中間節點沒什麼兩樣了,就可以簡化處理邏輯。
有了哨兵節點,我們就可以pre, cur := sentinel, head
。這樣當判定cur是要刪除的節點時候,pre.Next = cur.Next
就完成刪除了。管你cur是頭節點還是尾結點呢?
刪除節點,我們要考慮它是不是尾結點嗎?不需要,因爲啥呢,刪除尾結點時候,尾結點的Next是nil,把它賦給prev.Next 並不會產生panic。
解法
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func removeElements(head *ListNode, val int) *ListNode {
if head == nil {
return nil
}
sentinel := &ListNode{
Next: head,
Val: -1,
}
// pre 用於記錄上一個節點,這裏首先指向哨兵節點,cur就指向head節點
pre, cur := sentinel, head
for cur != nil {
if cur.Val == val {
// 如果當前節點與要刪除的一致,就把上一個節點的Next跳過當前節點,指向下一個
pre.Next = cur.Next
} else {
// 這裏的pre只用做記錄上一個節點。用於要刪除的時候,切換一下指向。
pre = cur
}
cur = cur.Next
}
return sentinel.Next
}