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

本文深入解析了链表反转的递归算法,通过逐步分解代码逻辑,详细解释了递归过程中的关键步骤,包括如何处理基本情况、如何实现节点的正确链接以及如何确保递归调用的正确返回。此外,还提供了完整的代码示例和测试用例,帮助读者理解并掌握链表反转的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 题目
/**
 * 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.youkuaiyun.com/chenghan_yang/article/details/94835745

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值