<循环不变式的思想>
题目描述
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
我的思路 - 迭代
class Solution: def reverseList(self, head: ListNode) -> ListNode: pre = None while head: t= head.next head.next = pre pre = head head = t return pre
-
算法:
-
遍历head结点,用 pre 标记 head 之前的结点,用 t 标记 head 之后的结点。
- head 结点 指向 pre 结点
- 继续下一个循环
我的思路 - 递归(误)
class Solution: def reverseList(self, head: ListNode) -> ListNode: if not head.next: return head ans = self.reverseList(head.next) # 回溯的时候head从5回到1,这时用ans来指向它(误) ans.next = head return ans
-
算法:
- 递归到底,返回尾结点
- 回溯的时候用ans指向当前栈帧的结点
-
存在的问题:
- 回溯的时候反转结点,这个思路可能导致最后return的是反转后的链表的尾结点(这里return ans就不会出现这个问题了)
- 最致命的一点:ans是递归到底得到的结果,回溯的时候把 ans 递给上一层,所以 ans 在这里是不会变的。那么什么时候会导致return的结果变化呢?参考这篇文章
题解 - 递归
class Solution(object): def reverseList(self, head): if not head.next: return head ans = self.reverseList(head.next) # 回溯的时候当前栈帧的结点是head,我们把head的下一个结点指向当前的head head.next.next = head head.next = None return ans
-
算法:
- 结合上面【我的思路】来看
总结
-
如何用循环不变式来思考?
- 考虑初始状态:比如设置虚拟头节点、确定第一次循环从哪个结点开始、等等
- 考虑保持状态(循环中):我们假设循环到结点P,且P之前的结点已经达到目的,专注于当前结点P该用什么样的算法。
- 考虑终止状态:主要是防止越界。。