1. 程式人生 > 實用技巧 >LeetCode#19. 刪除連結串列的倒數第N個節點

LeetCode#19. 刪除連結串列的倒數第N個節點

leetcode#19

給定一個連結串列,刪除連結串列的倒數第 n 個節點,並且返回連結串列的頭結點。

示例:

給定一個連結串列: 1->2->3->4->5, 和 n = 2.

當刪除了倒數第二個節點後,連結串列變為 1->2->3->5.

說明:

給定的 n 保證是有效的。

進階:

你能嘗試使用一趟掃描實現嗎?


解題思路:雙指標和滑動視窗,右指標先走n步,然後左右指標一起走。左指標一開始指向新增的一個啞節點(dummy node),它的next指標指向連結串列的頭節點。這樣一來,我們就不需要對頭節點進行特殊的判斷了。最後左指標指向倒數第 n+1 個節點,將它的 next 指向倒數第 n-1個節點。注意一個 或 兩個節點的情況。

// 方法一:雙指標+滑窗
func removeNthFromEnd(head *ListNode, n int) *ListNode {
    dummyHead := &ListNode{0, head}
    // 前後驅指標
    left, right := dummyHead, head
    for i := 0; i < n; i++ {
        right = right.Next
    }
    for ; right != nil; right = right.Next {
        left = left.Next
    }
    left.Next = left.Next.Next
    return dummyHead.Next
}
/*時間複雜度O(L)  空間複雜度O(1)*/

其他兩種方式

//方法二:先求長度,再遍歷到倒數n+1個, 刪除
func getLength(head *ListNode) (length int) {
    for ; head != nil; head = head.Next {
        length++
    }
    return
}

func removeNthFromEnd(head *ListNode, n int) *ListNode {
    length := getLength(head)
    dummy := &ListNode{0, head}
    cur := dummy
    for i := 0; i < length-n; i++ {
        cur = cur.Next
    }
    cur.Next = cur.Next.Next
    return dummy.Next
}
/*
時間複雜度:O(2L-n),其中 L 是連結串列的長度。
空間複雜度:O(1)。
*/
// 方法三:棧實現
func removeNthFromEnd(head *ListNode, n int) *ListNode {
    nodes := []*ListNode{}
    dummy := &ListNode{0, head}
    for node := dummy; node != nil; node = node.Next {
        nodes = append(nodes, node)
    }
    prev := nodes[len(nodes)-1-n]
    prev.Next = prev.Next.Next
    return dummy.Next
}
/*
時間複雜度:O(L)
空間複雜度:O(L) 主要為棧的開銷。*/