【算法】链表反转 -- 递归解法

25 篇文章 1 订阅
14 篇文章 0 订阅
  • 题目
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
     public ListNode reverseList(ListNode head) {
        
    }
}
  • 解题关键
  1. 基本情况:if (head.next == null) return head;
  2. 返回值如何处理才能串联成合适的逻辑。
    具体: 递归过程可以看作从蓝色 -> 橙色 -> 黑色 -> 绿色 -> 红色

在这里插入图片描述
链表反转递归到底的情况:4节点将成为头节点。用3,4,null的视图来看。
在这里插入图片描述

head.next.next = head;
head.next = null; // 断开原来连接

完成链表反转后,4也就成为了头节点。返回值应该是上层的head.next;
对应的代码可以到:

public ListNode reverseList(ListNode head) {
    if (head.next == null) return head;
    // 反转逻辑
    head.next.next = head;
    head.next = null;
    // 可以发现,head.next再上一步已经修改,于是在反转逻辑之前需要多一个引用来存储上层的head.next
    // return (上层的head.next);
}

进一步:

public ListNode reverseList(ListNode head) {
    if (head.next == null) return head;
	// 新增应用存储head.next;
	ListNode ret ; // 该引用需要递归完成,每一次执行该函数都会用到,具体职责有两个,见下文
    // 反转逻辑
    head.next.next = head;
    head.next = null;
    return ret;
}

进一步:新增引用存储递归到底的head.next,该引用同时还是递归调用的核心,具体职责:

  1. 保留递归到底的head.next,一直返回至应用层,本例就是val = 4的节点,所有递归都不会改变ret的值。
  2. 若未找到递归到底的情况,把head.next都压入系统栈。只要下层完成反转,上层才开始反转。
    间接实现对节点顺序访问倒叙操作
    1 -> 2 -> 3 -> 4 -> null
    1 -> 2 -> 3 <- 4 ret == 4
    1 -> 2 <- 3 <- 4 ret == 4
    null <-1 <- 2 <- 3 <- 4 ret == 4

值得注意的是

head.next = null; 
// 在最上层调用中也返回后,1 -> 2 变为 1 -> null; 
// 不仅是断开原来连接,还成功将原本头节点反转成尾节点
public ListNode reverseList(ListNode head) {
    if (head.next == null) return head;
	// 新增应用存储(不变的)头节点并完成递归
	ListNode ret = reverseList(head.next);
    // 反转逻辑
    head.next.next = head;
    head.next = null;
    return ret;
}
  • 空值处理,传入的head为NULL,返回本身;代码完成
public ListNode reverseList(ListNode head) {
    if ( head == null || head.next == null) return head;
	// 新增应用存储head.next并完成递归
	ListNode ret = reverseList(head.next);
    // 反转逻辑
    head.next.next = head;
    head.next = null;
    return ret;
}
  • 测试用例
public static void main(String[] args) {
        Solution s = new Solution();
        ListNode head = s.initListNode(1);
        head.buildNext(2).buildNext(3).buildNext(4);
        // Solution2.printList(head);
        ListNode newHead = s.reverseList(head);
        // Solution2.printList(newHead);
    }
private ListNode initListNode(int i) {
        return new ListNode(i);
    }
 private ListNode buildList(ListNode head, int i) {
        if (head == null) {
            throw new IllegalArgumentException("头节点不允许为空");
        }
        ListNode cur = head;
        while (cur.next != null) {
            cur = cur.next;
        }
         return cur.next = new ListNode(i);// 返回新增的节点的指针
    }
 public class ListNode {
        int val;
        ListNode next;
        ListNode(int x) { val = x; }

        private ListNode buildNext(int i) {
            return new Solution().buildList(this, i);
        }
    }

时间复杂度:O(n),空间复杂度:O(1)

  • 拓展
    链表反转迭代解法见:

https://blog.csdn.net/chenghan_yang/article/details/94835745

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值