📅  最后修改于: 2023-12-03 14:48:58.363000             🧑  作者: Mango
在本文中,我们将学习如何找到链表末尾的第 n 个节点。对于链表数据结构,遍历整个链表可以找到它的末尾节点。然而,我们也可以使用一些技巧在不遍历整个列表的情况下找到列表中的第 n 个节点。
一个找到倒数第 k 个节点的常规方式是通过反转链表来实现。我们可以反转链表,然后遍历 k 步并返回相应的节点。 在这个方法中,我们将创建一个新的链表,将原始链表的节点反转,遍历反向列表并从 n 到 n-k 返回第 n-k 个节点。
class Solution:
def reverseLinkedList(self, head: ListNode) -> ListNode:
prev = None
curr = head
while curr:
nextNode = curr.next
curr.next = prev
prev = curr
curr = nextNode
return prev
def findNthFromEnd(self, head: ListNode, n: int) -> ListNode:
if not head:
return None
reversed_head = self.reverseLinkedList(head)
curr = reversed_head
i = 1
while curr and i < n:
curr = curr.next
i += 1
if not curr:
return None
return curr.val
具体过程如下:
时间复杂度:$O(n)$,其中 n 是列表的长度。 这个算法遍历了该列表两次,首先是反向列表,然后从 n 到 n-k 返回第 n-k 个节点。但是需要注意的是,代码实现比遍历列表两次要简单。
空间复杂度:$O(1)$。 这个算法只需要常数级别的存储(创建一个新的链表)。
另一个方法是使用两个指针:快指针和慢指针。我们将两个指针都初始化为指向该链表的头部,然后将快指针向前移动 n 个节点。此时,双指针之间会有一个间隔为 n 的距离。接下来,我们将两个指针一起向前移动,直到快指针到达链表的末尾。此时,慢指针将指向链表的倒数第 n 个节点。
class Solution:
def findNthFromEnd(self, head: ListNode, n: int) -> ListNode:
dummyNode = ListNode(-1)
dummyNode.next = head
slow = fast = dummyNode
#移动 fast 指针,使其指向第n个节点,此时slow和fast之间的距离为n
for i in range(n):
fast = fast.next
#同时移动 slow 和 fast 指针
while fast.next:
slow = slow.next
fast = fast.next
#此时slow所指的为倒数第n个节点
return slow.next
具体过程如下:
时间复杂度:$O(n)$. 计算一次需要O(n)的时间,这里只遍历了一次列表。
空间复杂度:$O(1)$. 双指针调用中只使用了常量级别的额外指针。
这篇文章演示了许多方法,在不遍历整个链表的情况下找到链表中的第 n 个节点。其中反转链表和双指针是相对容易理解的,但是在面试中需要思考。 总体来说,这些技巧为在链表中找到节点提供了一种更加高效的方法,尤其是对于较长的链表而言。