Python:反转链表的三种方式 【算法村E2链表反转笔记(青铜)】

前言

反转链表是链表问题中相当常见的一类,在面试题中经常遇见,因此牢牢掌握很有必要~ 

本文提供反转链表的三种方式:第一种,迭代;第二种,迭代+虚拟头节点,第三种,递归

其中,迭代和递归是基本思想,“虚拟头节点”作为扩展。

(部分思想来源于算法村、labuladong算法小抄、以及热心的群u~)

(在链表中某个节点node、某个链表listnode大部分情况下指代的是同一个东西,有节点就会有链表、有链表就会有节点,下文中也有如此写法,希望不会产生混淆。)


目录

迭代法

融合虚拟头节点的迭代

递归法


迭代法

直接上代码:

pre,cur,nxt = None,head,head
while cur:
    nxt = cur.next
    cur.next = pre
    pre = cur
    cur = nxt
return pre

我们来简单看一下思路:

首先,为了方便理解,请忽略掉nxt,这是中继变量,暂时不考虑。

为了依次将链表进行反转,我们最先要做的事情就是确立使用while函数遍历链表。随便设定一个cur=head,当cur不是空的时候往后遍历即可。

为了遍历,我们知道一定会有cur=cur.next这么一步。但在本题中,由于某种原因,我们提前用nxt保存了cur.next,while的最后让cur=nxt,完成遍历的操作。

在while里写什么呢?

我们假设有这么一个pre,它能够代表已经经过处理、变成倒序的链表(例如:原本完整链表是1 -> 2 -> 3 -> 4 -> 5,pre代表了3 -> 2 -> 1)。

并且假设cur是pre的下一个节点(例如:cur是4,pre是上述部分倒序链表),那么我们要做的工作显而易见:将cur指向pre,使得4 -> 3 -> 2 -> 1。值得注意的是:完成这一步的时候,pre本身没有变化,我们只是对cur进行了操作。

做好这一步之后,我们发现cur代表了值为4的节点(4 -> 5),pre代表了3的节点(3 -> 2 -> 1),因此应该让pre和cur都往后平移一格。pre = cur和cur = nxt(我们知道这个nxt实际上就是原本的cur.next)

好了,现在pre是4(4 -> 3 -> 2 -> 1),cur是5(5 -> None),对其自动执行如上操作即可。直到判断cur为None的时候停止。

看起来一切都很妥当,除了一个问题:即使我们完成了遍历,看起来也只是(5 -> 4 -> 3 -> 2 -> 1)啊,1不应该接着指向None嘛?

好问题~不过其实我们在最开始就解决了:因为cur=head(1),pre=None,所以第一次cur.next = pre的时候我们就自动完成了(1 -> None)。


融合虚拟头节点的迭代

dummy = ListNode(-1)
cur = head
while cur:
    nxt = cur.next
    cur.next = dummy.next
    dummy.next = cur
    cur = nxt
return dummy.next

关于什么是虚拟头节点,请参照专栏的前文,那里有一些简短的“科普”。

基本思路与上面一模一样,只不过把所有的pre换成了dummy.next


递归法

先看代码:

def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
    # 递归
    if not head or not head.next:
    last = self.reverseList(head.next)
    head.next.next = head
    head.next = None
    return last

对于一个递归函数,最重要的地方是:我们要明确递归函数的定义

在本题中,我们让递归函数可以反转输入进去的链表(功能),并且返回反转后链表的头节点(返回值)

好了,我们假设头节点还是头节点(1),指向的是已经被反转的后续链表(5 -> 4 -> 3 -> 2),这个被反转链表的头节点是5。

显然,节点2的next是空的,我们要让它指向1。该怎么写呢?

我们知道尽管后续链表已经改变,然而头节点1和它的后续关系没有改变,即head.next依然是节点2。所以我们只需要head.next.next=head即可。(看起来很喜感(

现在以last(本题中是5)为头节点的反转链表已经扩展到了(5 -> 4 -> 3 -> 2 -> 1),而我们只需要再让head.next=None,让1指向None,即可完成所有的转变~

你可能想知道实际过程中递归函数的运行过程,但不是很建议这么做:理解递归最好的方式是拆分任务、处理好单个任务,然后剩下的全部交给计算机自己做吧。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值