LeetCode链表反转解法理解

1 篇文章 0 订阅
1 篇文章 0 订阅

一、题目

反转一个单链表 如输入: 1->2->3->4->5->NULL;输出: 5->4->3->2->1->NULL

二、解析

1.最简单的解法是遍历链表,将元素的next的指针指向前一个元素。思路有了,接下来就是写代码了但是由于是个单向列表所以其实是拿不到前一个元素的,这个时候就需要有个变量来保存前一个元素。另外还得有个变量来保存需要更改next指针的元素;代码如下

public ListNode reverseList(ListNode head) {
//保存前一个节点
    ListNode prev = null;
//保存当前要更改next的指针的节点
    ListNode curr = head;
//当curr==null的时候表示已经到了末尾,就不需要再变了
    while (curr != null) {
        ListNode nextTemp = curr.next;
        curr.next = prev;
        prev = curr;
        curr = nextTemp;
    }
    return prev;
}

该解法的时间复杂度是O(n),因为链表有几个元素就循环了几次。空间复杂度为O(1)只使用了两个临时变量来保存中间数据,没有额外的空间消耗

2.上面的解法是最简单的,也是大多数人都能第一时间想到的,包括我自己,然后翻看LeetCode的答案,发现还有一个更骚的递归的解法。说实话我第一次看是完全不理解。只能把代码复制出来放到ide里面去debug,然后自己纸上作图,花了半天才理解了这个递归流程。写这篇博客的主要原因也是为了加深理解和记忆。话不多说,往下看推理:

  首先思路是要反向推理。假设链表的后面几个已经是反向好了的,那这个时候需要反向之前的需要怎么做呢?

 比方说有一个链表 n1->n2->....->n(k-1)->n(k)->n(k+1)->....n(m)->null

假设k+1往后都已经反转好 即 n1->n2->....>n(k-1)->n(k)->n(k+1)<-n(k+2)<-......<-n(m-1)<-n(m);

这个时候需要将n(k+1)的next指针指向n(k)方案就是n(k).next.next=n(k) 也就是将第K个元素的下一个元素的的next指针指向他本身就可以了。然后还必须把n(k)的next指针指向null 如果不这么做的话就会变成一个环 即变成下面的效果n(k)->n(k+1)->n(k)->n(k+1)

如下图 释放n(k)的next指针后环才会没有.那依靠这个思路,可以看代码如下

public ListNode reverseList(ListNode head) {
//1
    if (head == null || head.next == null) return head;
//2
    ListNode p = reverseList(head.next);
//3
    head.next.next = head;
//4
    head.next = null;
//5
    return p;
}

要理解这段代码,需要通过一个简单的case来说明。先假设一个长度为5的链表 元素分别为1,2,3,4,5 结构就类似

1->2->3->4->5->null(没有表示5是尾节点);

然后再看代码 第一行是判断当前是null或者当前的下一个为null就表示已经是尾节点。尾节点就不需要做什么操作了。

主要的骚操作个人觉得是第二行代码即 ListNode p= reverseList(head.next) 每次递归传入的是当前元素的下一个元素。

所以该递归的终止边界其实是链表的倒数第二个节点 因为倒数第二个节点即例子里面的4的下一个节点为5,5的next就为null,递归就终止了。执行完第二行 head=4 p=5这个需要记住 。head的结构是4->5 然后代码执行到第三行。把head.next.next=head的含义就是将5的next指针指向4 这个时候head的结构就是 4->5->4其实是个环 p的结构是5->4->5也是个环。最关键的是第四步,将head.next=null这个时候环就断开了 head的结构就变成了4->null p的结构是5->4->null 这个也很好理解因为4的next指针变为了null。还得记住代码返回的是p而不是head这很重要。这次的方法已经执行结束,弹出栈然后执行下一个方法还是reverseList方法

这次执行第二行拿到的p是刚才返回的5,结构为5->4 head是3,结构其实是3->4->null 4指向null是刚才一次操作 然后执行第三行。head.next.next=head 执行完之后head为 3->4->3->4其实是个环但是有执行完第四行 head变成了 3->null, p其实变成了5->4->3->null;后续两次操作也是类似的推导.当执行完之后p的结构就变成了5->4->3->2->1-null 就达到了反转的效果。递归的方法很骚,很不容易理解,需要debug来看,当然也不排除有大佬一下子就理解了。递归的方法的时间复杂度是O(n)因为有几个元素就会递归几次。空间复杂度也是O(n)因为每次递归都会产生一个隐士栈空间,所以就是O(n)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值