剑指 Offer 24. 反转链表 LCOF

JAVA

① 逐个反转

在这里插入图片描述

public class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode ans = null;
        while (head != null) {
            ListNode tmp = head.next;
            head.next = ans;
            ans = head;
            head = tmp;
        }
        return ans;
    }
}

动态图来自LeetCode题解

其实我感觉并不是很好理解 (却是最常用的) ,这种方法属于重新创建链表 ans 但也用到了原链表 head,每次将 head 链表反转一个结点,同时又用 ans 替代了原 head,一直持续到 null

② 神奇的递归

在这里插入图片描述

public class Solution {
    public ListNode reverseList(ListNode head) {
        if (head == null || head.next == null)
            return head;
        ListNode tmp = reverseList(head.next);
        head.next.next = head;
        head.next = null;
        return tmp;
    }
}

动态图来自LeetCode题解

思路是先一路递归到最后,每次调用回来的时候,先让 tmp 赋值为上次调用回来的 head,再让当前的 headnext.next 赋值为 head(也就是数组下标为 head 的节点,它所指向的节点指向回自己),而 head(自己)赋值为 null(指向空),最后返回 tmp

没错,挺有趣的解法,但当我写完后一直有个很困惑的点,就是为什么 tmp 赋值为 head.next 后,当 head.next.next 改变了,tmp.next 也跟着改变了?(因为最后传递的是 tmptmp 原本是指向数组的 null,但最后输出的是反转后的数组,所以推出 tmp.next 也变了)

为了验证,我写了下面的代码

//head  x  xx
ListNode head = new ListNode(4);
ListNode x = new ListNode(5);
ListNode xx = new ListNode(100);
head.next = x;
x.next = xx;

ListNode tmp = head.next;
System.out.println(tmp.next.val);   // 100
head.next.next = head;
System.out.println(tmp.next.val);   // 100
head.next = null;
System.out.println(tmp.next.val);   // 100

我仿照样例给出数组为 [1,2,3,4,5] 的简化链表,上面例子中 head 相当于 4x 相当于 5xx 相当于 null,和原代码一样,但在每个步骤后都输出一次 tmp.next 的值,看是否会发生变化(注释后面是我以为会得到的值)

打印如下:

100
4
4

很明显我想错了,于是我:

head.next.next = head;

改成

xx = head

打印如下:

100
100
100

那么结果很显然了,head.next.next 确实可以影响 tmp.next

我给出的解释是:head.next.next 的第二个 next 相当于 C语言 的指针,其改变的不是值,而是指向的地址
(这就是没有指针的 JAVA 吗?爱了爱了)

Python

① 逐个反转

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        ans = None
        while head:
            head.next, ans, head = ans, head, head.next
        return ans

这用的其实就是第一种方法的思想,仔细看看 JAVA 的代码的话,就会发现实质就是三个变量在相互赋值(head.next 、ans 、head

注意:用平行赋值语法,系统会自动生成一个 tmp 储存 head.next,并从前往后依次赋值

② 神奇的递归

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        def reans(ans, pre):
            if not ans: return pre     # 终止条件
            res = reans(ans.next, ans) # 递归后继节点
            ans.next = pre             # 修改节点引用指向
            return res                 # 返回反转链表的头节点
        
        return reans(head, None)       # 调用递归并返回

LeetCode图解(看了这个就懂了)

但和 JAVA 一样,总觉得用递归非常不直观,传参和调用中暗藏着看不见的指针在作怪

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值