剑指offer—反转链表(有图解)

题目:输入一个长度为 链表,反转链表后,输出新链表的表头。
数据范围n≤1000
要求:空间复杂度O(1),时间复杂度O(n)。

  拿到这道题的第一瞬间,小白思维直接给出了解题答案,直接把链表变成数组,逆序之后再变成链表不就好了,确实,我按照这个方法写出的代码确实能提交,也通过了。但当我打开解题区后傻眼了,我意识到自己好像是一个四肢发达头脑简单的生物QAQ,看了一天代码才理解了皮毛。
以下是题解区的大佬代码,加上自己的理解吧,防止下次看的时候又看不懂了,解释写的较为粗糙,你们可能看不懂,我肯定看得懂(哈哈哈)

常规方法

  第一个,由于题解区给出的是Java代码,我只能照葫芦画瓢,可能有语法上的错误(我感觉好像没问题)

class ListNode():
    def __init__(self, x):
        self.val = x
        self.next = None
class Solution:
	def ReverseList(self, pHead):
        if pHead is None:
            return None
        pre = None
        next = None
        while pHead:
            next = pHead.next # 记录pHead的下一个节点位置
            pHead.next = pre # 使pHead指向pre
            pre = pHead # pre向下移动一个节点
            pHead = next # pHead向下移动一节点
        return pre

防止看不懂,下面这些算是对代码的注释吧(这些图都拿PS做的,人都快傻了,现学现卖,不过我选的这颜色是真的好看)
pre指向当前节点的前一个节点
next指向当前节点的后一个节点
假设有四个节点,那其运行的过程如下
1.初始链表元素为A、B、C、D,进入循环前已经将pre和next定义为None

2.当A节点不为空的时候进入循环,记录A的下一个节点位置next=B,然后让A的指针指向pre,也就是A.next=pre。(此时对应循环中的next=pHead.next和pHead.next=pre),下图按代码分步骤说明:
  (1)next=pHead.next,next存储pHead的下一个节点,此时pHead的节点为A,所以pHead.next为B节点

  (2)pHead.next=pre,让A的指针指向pre,也就是让A.next=pre

3.让pre和pHead继续向下走。让pre指向pHead节点来实现pre的移动,因为上一步中记录了A节点的下一个节点,即next,让pHead指向next来实现头指针pHead的移动。(此时对应循环中的pre=pHead和pHead=next)。以下按代码步骤说明:
  (1)pre=pHead,实现pre的向下一节点移动

  (2)pHead=next,头指针pHead向下移动,此时next并未更新,所以不变,指向的仍是B节点(进入下一循环才会重新赋值)

4.接下来就重复循环,next指向pHead的下一节点C,pHead指向pre,然后pre和pHead再向下移动一节点,如下图

5.继续循环

6.最后一次循环,next指向pHead的下一个节点,但是此时的pHead为D节点,其下一节点为None,pHead指向next,因此也为None,所以退出循环。此时返回pre则是链表反转后的头指针。

变量交换

  第二个的代码写的非常的巧妙,苦逼的我看不懂,到处查,然后找别人给我讲,但是写的真的很好,看完之后整个精神都升华了(痴汉脸),通过这个代码也让我对指针的结构有了新的认识和理解,也算是收获不菲吧

class ListNode():
    def __init__(self, x):
        self.val = x
        self.next = None
class Solution:
    def ReverseList(self, pHead):  # 变量交换
        if pHead is None:
            return None
        root = None
        while pHead:
            pHead.next, root, pHead = root, pHead, pHead.next
        return root

我本人才能看的注释
  root相当于第一种方法的pre,也就是得到反转链表以后的头指针吧
反正这代码我没看懂(万年老菜鸟了),我参考了下面这大佬的解释才理解
Python 多变量赋值的机制(以反转链表为例)
下面就配上我自己的理解,加上大佬的思路,把代码运行的过程图画一画
其实把大佬的文章认真读了应该都能懂,我再画一遍加深一下印象
1.老规矩,原始链表的样子

2.把变量交换拆成三步,这样交换变化的过程更加清晰,也容易理解,对我来说 ,本身变量交换为pHead.next,root,pHead=root,pHead,pHead.next,我就拆成pHead.next=root,root=pHead,pHead=pHead.next三步
  (1)pHead.next=root,先让A节点指向root

  (2)root=pHead,root向下一节点移动

  (3)pHead=pHead.next,前两步可能没什么问题,顺理成章,第三步看着图的话就有点懵逼,pHead.next难道不是None吗?怎么pHead指向了B节点?这个时候就不得不说我上面给出的链接有多香了。python变量交换的时候,会先将右边各项的值计算出来保存起来,计算的时候使用的都是左边给出的初始值,计算期间诞生的中间值并不会被拿去用于新的计算。在这个步骤中第一步里,pHead.next虽然已经被赋值为root,所以pHead已经被指向None,但是在计算后面pHead=pHead.next的时候pHead要等于None吗?当然不是,这样的话代码就凉了,在左边初始值中的pHead.next指向的仍是B节点,并没有受到前面变量交换的影响。(这代码巧在利用python变量交换的特点,因此不需要来存储当前节点的下一节点,也就是第一种方法省略了next变量)

3.进入下一轮循环
在这里插入图片描述
4.继续下一轮循环
在这里插入图片描述
5.最后一轮循环,pHead指向D的下一个节点,也就是None,root也成为了反转后链表的头指针

递归法

  第三个采用的是递归方法,看递归代码对我来说真的是一种折磨,但代码却又写的很好,我又非常想深入了解其中的原理,顺嘴提一句,我本来想使用debug来帮助我更好的了解这个代码,结果却起了反作用,那变量监视差点让我疯掉(抓狂……)

class ListNode():
    def __init__(self, x):
        self.val = x
        self.next = None
class Solution:
    def ReverseList(self, pHead):  # 递归
        if not pHead:
            return None
        if not pHead.next:
            return pHead
        headNode = self.ReverseList(pHead.next)
        pHead.next.next = pHead
        pHead.next = None
        return headNode

递归法的解释嘛…能力有限(本人菜的很),代码理解了,但是流程图的话……有点难画,有机会的话一定补上……

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值