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) 主要为栈的开销。*/
posted @ 2020-11-22 11:37  devhg  阅读(105)  评论(0编辑  收藏  举报