160. 相交链表
python
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:
p, q = headA, headB
while p is not q:
if p:
p = p.next
else:
p = headB
if q:
q = q.next
else:
q = headA
return q
-
初步思路标题(哈希集合法) :
最直接的解法是遍历第一个链表,将所有节点存入哈希集合,然后遍历第二个链表检查是否有节点在集合中。这种方法虽然直观,但需要O(m)或O(n)的额外空间,不符合空间复杂度O(1)的要求。
-
优化思路标题(双指针交替遍历法):
-
优化方向1:利用两个指针分别从两个链表头开始遍历,当指针到达末尾时,将其重定向到另一个链表的头部
-
优化方向2:通过这种交替遍历的方式,两个指针最终会在相交节点相遇,或者同时到达末尾(null)
-
-
关键策略优势:
-
策略带来的具体好处1:无需额外存储空间,空间复杂度降为O(1)
-
策略带来的具体好处2:通过消除长度差,确保两个指针在第二次遍历时能够同步到达相交点
-
策略带来的具体好处3:代码简洁,只需要简单的指针操作即可实现
-
-
具体实现:
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:
p, q = headA, headB
# 当两个指针不相遇时继续遍历
while p is not q:
# p指针移动到下一个节点,如果到达末尾则从headB开始
if p:
p = p.next
else:
p = headB
# q指针移动到下一个节点,如果到达末尾则从headA开始
if q:
q = q.next
else:
q = headA
# 返回相遇节点(如果没有相交,则返回null)
return q
206. 反转链表
python
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
p = None
c = head
while c:
n = c.next
c.next = p
p = c
c = n
return p
-
初步思路标题(借助外部数组法) :
最直观的解法是遍历链表将所有节点值存入数组,然后反向遍历数组重新构建链表。这种方法虽然易于理解,但需要O(n)的额外空间存储节点值,且破坏了原链表的结构,不符合题目对原地反转的隐含要求。
-
优化思路标题(迭代指针反转法):
-
优化方向1:使用三个指针(前驱p、当前c、后继n)在遍历过程中逐步反转每个节点的指向
-
优化方向2:通过保存当前节点的下一个节点,防止在改变指向后丢失后续节点的访问能力
-
-
关键策略优势:
-
策略带来的具体好处1:只需遍历一次链表,时间复杂度为O(n)
-
策略带来的具体好处2:仅使用三个指针变量,空间复杂度为O(1),实现真正的原地反转
-
策略带来的具体好处3:能够正确处理空链表和单节点链表的边界情况
-
-
具体实现:
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
p = None # 前驱指针,初始为None
c = head # 当前指针,从链表头开始
while c: # 当当前节点不为空时继续遍历
n = c.next # 保存下一个节点,防止丢失
c.next = p # 将当前节点的next指向前驱,完成反转
p = c # 前驱指针移动到当前节点
c = n # 当前指针移动到下一个节点
return p # 返回新的头节点(原链表的最后一个节点)
python
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head or not head.next:
return head
n = self.reverseList(head.next)
head.next.next = head
head.next = None
return n
-
初步思路标题(迭代指针反转法) :
常规解法是使用三个指针迭代遍历链表,逐个反转节点的指向。这种方法直观且高效,但需要手动维护指针关系,代码相对繁琐。
-
优化思路标题(递归回溯反转法):
-
优化方向1:利用递归调用栈天然的后进先出特性,先递归到链表末尾,然后在回溯过程中逐步反转指针方向
-
优化方向2:将问题分解为"反转当前节点之后的链表"这一子问题,通过递归调用解决子问题后再处理当前节点
-
-
关键策略优势:
-
策略带来的具体好处1:代码极其简洁优雅,只需几行就能实现完整功能
-
策略带来的具体好处2:递归思路更符合数学归纳法的思维方式,易于理解和证明正确性
-
策略带来的具体好处3:虽然使用调用栈(空间复杂度O(n)),但在链表反转的场景中通常也是可接受的
-
-
具体实现:
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
# 递归终止条件:空链表或只有一个节点
if not head or not head.next:
return head
# 递归反转后续链表,返回新的头节点
n = self.reverseList(head.next)
# 关键步骤:将当前节点的下一个节点的next指向当前节点
# 例如:原链表 ... -> head -> next -> ...
# 反转后变为 ... -> next -> head -> ...
head.next.next = head
head.next = None # 防止形成环
return n