206.反转链表

 <循环不变式的思想>

题目描述


 

反转一个单链表。

示例:

输入: 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

 

  • 算法: 

  1. 遍历head结点,用 pre 标记 head 之前的结点,用 t 标记 head 之后的结点。

  2. head 结点 指向 pre 结点
  3. 继续下一个循环

 

 

 

我的思路 - 递归(误)


 

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
  • 算法:

  1. 递归到底,返回尾结点
  2. 回溯的时候用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该用什么样的算法。
    • 考虑终止状态:主要是防止越界。。

 

posted @ 2019-08-24 22:45  remly  阅读(190)  评论(0编辑  收藏  举报