利用链表的递归性质求解“链表翻转”问题

来源:5-7 更多和链表相关的问题

next_n

2019-02-25

老师您好,我在刷题时遇到了“翻转链表”这个问题,题目如下:
输入一个链表,反转链表后,输出新链表的表头。
比如 1->2->3->4->5 要变成 1<-2<-3<-4<-5
当然,这个问题很简单,用普通方法可以简单得到如下解:
(1)非递归思路

public class Solution {
        public ListNode ReverseList(ListNode head) {
            if(head == null) return null;
            if(head.next == null) return head;
            ListNode p = ReverseList(head.next);
            ListNode q = p;
            while (q.next != null){
                q = q.next;
            }
            q.next = head;
            return p;
        }
    }

但是听了你的课以后,我一直尝试用递归的思想去求解这个问题,(但是出现了问题,所以特地来这一章节向您提问)解法如下:
(2)递归思路求解

public class Solution {
    public ListNode ReverseList(ListNode head) {
	    //递归到底的结果
        if(head == null) return null;
        if(head.next ==null) return head;
        //假设ReverseList(head.next)已经将以head.next为头结点的链表翻转;
        //同时返回翻转后链表的头节点reverse_head_next
        //那么接下来的工作就是将head节点加入这个翻转后的链表里。
        ListNode reverse_head_next = ReverseList(head.next);
        //q用来遍历到链表的末尾,"接住"head;
        ListNode q = reverse_head_next;
        while (q.next != null){
            q = q.next;
        }
        q.next = head;
        return reverse_head_next;
        }
    }

当然这个解法是错的,bobo老师能否帮忙看看错在哪里?

写回答

3回答

liuyubobobo

2019-02-26

你的算法思路没有问题。我在Leetcode上测试了一下你的代码(206号问题),会报超时。


原因在于,你的这个递归算法,是一个O(n^2)复杂度的算法。可以想象一下,每一次递归调用,你都确定了一个节点如何和剩下的节点进行连接。为了确定这个连接方式,你还需要遍历一遍剩下的所有节点。所以整体是O(n^2)的。而相应的非递归算法是O(n)的:)


解决方法很简单。我们不能每次递归调用“遍历到链表的末尾”,看能否能直接获得翻转链表的末尾?当然可以啦!翻转后链表的末尾,就是翻转前链表的头啊!范赚钱链表的头,就是head.next啊!:)


我修改的代码如下:

public class Solution {
    public ListNode reverseList(ListNode head) {
        //递归到底的结果
        if(head == null) return null;
        if(head.next ==null) return head;
        
        //假设ReverseList(head.next)已经将以head.next为头结点的链表翻转;
        //同时返回翻转后链表的头节点reverse_head_next
        //那么接下来的工作就是将head节点加入这个翻转后的链表里。
        ListNode reverse_head_next = reverseList(head.next);
        
        // 上面的代码递归处理完了head.next对应的链表
        // 下面的代码用来维护head
        ListNode reverse_tail = head.next; // 这个变量不声明也可以,声明语义更清晰:)
        reverse_tail.next = head;
        head.next = null;
        
        return reverse_head_next;
    }
}


继续加油!:)

0
3
liuyubobobo
回复
从人从韦
大赞!所谓的递归宏观语义:)感谢分享:)
2019-05-12
共3条回复

next_n

提问者

2019-02-25

很尴尬。。非递归思路贴错了(贴成了和下面递归思路一样的),不过就是常规方法,很简单。就不再贴了。麻烦帮忙看看“递归思路”的错误。

0
0

next_n

提问者

2019-02-25

//ListNode 定义如下:

public static class ListNode {
   int val;
   ListNode next = null;

   ListNode(int val) {
       this.val = val;
   }
}

0
0

玩转数据结构

动态数组/栈/队列/链表/BST/堆/线段树/Trie/并查集/AVL/红黑树…

6221 学习 · 1704 问题

查看课程