力扣Hot100--206.反转链表
力扣Hot100–206.反转链表
要求:给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
解题思路:
1、使用列表存储节点后重新连接的方式实现了链表反转
缺点:空间复杂度为 O(n),因为需要额外的列表来存储所有节点的引用
比较常见的解法就是迭代法和递归法
迭代:
时间复杂度:O(n),其中 n 是链表的长度。空间复杂度:O(1)。
递归:
时间复杂度:O(n),其中 n 是链表的长度。空间复杂度:O(n),其中 n 是链表的长度。
本方法:时间复杂度:O(n),其中 n 是链表的长度。空间复杂度:O(n),其中 n 是链表的长度。
代码:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:if head is None:return Nonemode_set =[]current = headwhile current:mode_set.append(current)current = current.nextn = len(mode_set)for i in range(n-1,0,-1):mode_set[i].next = mode_set[i-1]mode_set[0].next = Nonereturn mode_set[-1]
迭代法:
class Solution:def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:prev = None curr = headwhile curr:next_node=curr.nextcurr.next = prevprev = currcurr = next_nodereturn prev
前两次的循环过程:
初始状态:
链表: 1 → 2 → 3 → 4 → 5 → None
prev = None
curr = 1(指向头节点)
第一次循环:
步骤 1: next_node = curr.next
保存 curr(节点1) 的下一个节点 (节点2),防止断链。
prev = None
curr = 1 → 2 → 3 → 4 → 5 → None
next_node = 2 → 3 → 4 → 5 → None
步骤 2: curr.next = prev
反转指针,让 curr(节点1) 的 next指向 prev(None)。至此,节点1成为了新链表的尾部。
(链表暂时被切断为两部分)
prev = None
curr = 1 → None
next_node = 2 → 3 → 4 → 5 → None
步骤 3: prev = curr
将 prev指针移动到当前已反转部分的头节点,即节点1。
prev = 1 → None
curr = 1 → None
next_node = 2 → 3 → 4 → 5 → None
步骤 4: curr = next_node
将 curr指针移动到之前保存的下一个节点,即节点2,准备处理下一个节点。
prev = 1 → None
curr = 2 → 3 → 4 → 5 → None
next_node = 2 → 3 → 4 → 5 → None
第二次循环:
步骤 1: next_node = curr.next
保存 curr(节点2) 的下一个节点 (节点3)。
prev = 1 → None
curr = 2 → 3 → 4 → 5 → None
next_node = 3 → 4 → 5 → None
步骤 2: curr.next = prev
反转指针,让 curr(节点2) 的 next指向 prev(节点1)。现在节点2连接到了节点1的前面。
(已反转部分变为 2→1→None)
prev = 1 → None
curr = 2 → 1 → None
next_node = 3 → 4 → 5 → None
步骤 3: prev = curr
将 prev指针移动到当前已反转部分的新头节点,即节点2。
prev = 2 → 1 → None
curr = 2 → 1 → None
next_node = 3 → 4 → 5 → None
步骤 4: curr = next_node
将 curr指针移动到之前保存的下一个节点,即节点3,准备处理下一个节点。
prev = 2 → 1 → None
curr = 3 → 4 → 5 → None
next_node = 3 → 4 → 5 → None
递归法:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:if(head is None or head.next is None):return headnewhead = self.reverseList(head.next)head.next.next = headhead.next = Nonereturn newhead
阶段一:递
第一次调用: reverseList(节点1)
不满足终止条件(节点1.next是 节点2, 不为空)。
执行 new_head = self.reverseList(节点2),等待递归结果。
第二次调用: reverseList(节点2)
不满足终止条件(节点2.next是 节点3, 不为空)。
执行 new_head = self.reverseList(节点3),等待递归结果。
第三次调用: reverseList(节点3)
满足终止条件!因为 节点3.next是 None。
函数返回 节点3(head=节点3)。这是递归的转折点。
reverseList(节点3)的返回值 节点3将成为新链表的头节点 (new_head),并开始逐层回溯。
阶段二:归
递归调用栈开始逐层返回结果并执行后续调整指针的代码。这是反转发生的地方。
返回到第二次调用 的地方(reverseList(节点2)的上下文)
new_head拿到了从第三次调用返回的 节点3 (new_head= 节点3)。
开始执行后续代码:
head.next.next = head;-> 此时 head是 节点2,head.next是 节点3。让 节点3的next 指向 节点2。 (3 -> 2)
head.next = None;-> 让 节点2的next 指向 None。
最后,返回 new_head(节点3)。
此时链表状态: (节点3) -> (节点2) -> None,节点1还未被处理,仍指向 节点2。
返回到第一次调用 (reverseList(节点1)的上下文)
new_head拿到了从第二次调用返回的 节点3。
开始执行后续代码:
head.next.next = head;-> 此时 head是 节点1,head.next是 节点2。让 节点2的next 指向 节点1,修改上次结果((节点2) -> None)。 (2 -> 1)
head.next = None;-> 让 节点1的next 指向 None,使其成为新链表的尾节点。
最后,返回 new_head(节点3)。
此时链表状态: (节点3) -> (节点2) -> (节点1) -> None。
最终结果: 链表成功反转为 3 -> 2 -> 1 -> None。函数返回的新头节点是 节点3。