今是昨非

今是昨非

日出江花红胜火,春来江水绿如蓝

鏈表的雙指針算法

Algorithem_TwoPointersOfLinked List#

876. 鏈表的中間節點#

給定一個單鏈表的頭節點,返回鏈表的中間節點。

如果有兩個中間節點,返回第二個中間節點。

範例 1:

Input: head = [1,2,3,4,5]
Output: [3,4,5]
Explanation: 鏈表的中間節點是節點 3。

範例 2:

Input: head = [1,2,3,4,5,6]
Output: [4,5,6]
Explanation: 由於鏈表有兩個中間節點,值為 3 和 4,因此返回第二個。

解法#

單看例子,感覺是獲取數組中間位置到末尾,這個跟 TwoPointer 有什麼關係呢?看到給的代碼,明白了,不是數組,給出的是一個 ListNode

定義的代碼如下:


/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public var val: Int
 *     public var next: ListNode?
 *     public init() { self.val = 0; self.next = nil; }
 *     public init(_ val: Int) { self.val = val; self.next = nil; }
 *     public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; }
 * }
 */
class Solution {
    func middleNode(_ head: ListNode?) -> ListNode? {

    }
}

這裡一開始沒理解給出的 ListNode 和上面範例中的 head 是怎麼對應起來的。

看了好久明白了,

鏈表
1 -> 2 -> 3 -> 4 -> 5

val     1
next    2

val     2
next    3

val     3
next    4

val     4
next    5

val     5
next    nil

理解了 listNode 之後,那如何獲取中間的 ListNode 呢?

定義兩個變量,s 和 f,每次循環 s 指向下一個元素,而 f 指向下下個元素,這樣最後 f 結束時,s 指向的就是中間。


/*
最開始
f
1 -> 2 -> 3 -> 4 -> 5
s

第一次循環
		  f
1 -> 2 -> 3 -> 4 -> 5
     s
	 
第二次循環
		            f
1 -> 2 -> 3 -> 4 -> 5
          s

第三次循環
當 f 的 next 為空時結束,此時 s 指向的是中間

f = fast pointer
s = slow pointer
*/

最終代碼如下:


/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public var val: Int
 *     public var next: ListNode?
 *     public init() { self.val = 0; self.next = nil; }
 *     public init(_ val: Int) { self.val = val; self.next = nil; }
 *     public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; }
 * }
 */
class Solution {
    func middleNode(_ head: ListNode?) -> ListNode? {
        var slow = head
        var fast = head
        while (fast != nil) && (fast?.next != nil) {
            slow = slow?.next
            fast = fast?.next?.next
        }
        return slow
    }
}

19. 刪除鏈表的倒數第 N 個節點#

給定一個鏈表的頭節點,刪除鏈表的倒數第 n 個節點並返回其頭節點。

範例 1:

Input: head = [1,2,3,4,5], n = 2
Output: [1,2,3,5]

範例 2:

Input: head = [1], n = 1
Output: []

範例 3:

Input: head = [1,2], n = 1
Output: [1]

解法#

這個地方,需要注意的是 nth node from the end of the list,是從末尾數第幾個。

想法是首先獲取整個長度,然後整個的長度減去 (n - 1),就是正著數的第幾個,從 1 開始的,然後賦值,從頭開始賦值,如果剛好到這個時,則跳過。
但是使用 TwoPoint 的算法是,定義 slow 和 fast,然後先讓 fast 向前走 n 步,再 slow 和 fast 一起向前走,這樣當 fast 走到尾部時,slow 剛好要移除的位置,然後跳過這個元素賦值。

代碼如下:


/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public var val: Int
 *     public var next: ListNode?
 *     public init() { self.val = 0; self.next = nil; }
 *     public init(_ val: Int) { self.val = val; self.next = nil; }
 *     public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; }
 * }
 */
class Solution {
    func removeNthFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? {
        let node = ListNode(0, head)
        
        var slow: ListNode? = node
        var fast: ListNode? = node
        
        var m = n
        while (m > 0) {
            fast = fast?.next
            m -= 1
        }
        
        while fast?.next != nil {
            slow = slow?.next
            fast = fast?.next
        }
        
        slow?.next = slow?.next?.next
        
        return node.next
    }
}

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。