递归解决反转链表的一部分

迭代思想:

先用一个 for 循环找到第 m 个位置,然后再用一个 for 循环将 m 和 n 之间的元素反转。但是我们的递归解法不用一个 for 循环,纯递归实现反转。
迭代实现思路看起来虽然简单,但是细节问题很多的,反而不容易写对。相反,递归实现就很简洁优美,下面就由浅入深,先从反转整个单链表说起。

递归反转整个链表

ListNode reverse(ListNode head) {
    if (head.next == null) return head;
    //last是反转后的头结点
    ListNode last = reverse(head.next);
    
    head.next.next = head;
    head.next = null;
    return last;
}

上述代码是不是优雅有难以理解?

  1. 想要理解递归代码,首先要明确递归的定义
  2. 遇到递归千万不要把思维跳进递归栈里,你的脑子够想几层递归
  3. 而是要思考该递归执行完成的结果是什么(根据定义)

语句解析:




反转前n个节点

ListNode successor = null; // 后驱节点

// 反转以 head 为起点的 n 个节点,返回新的头结点
ListNode reverseN(ListNode head, int n) {
    if (n == 1) { 
        // 记录第 n + 1 个节点
        successor = head.next;
        return head;
    }
    // 以 head.next 为起点,需要反转前 n - 1 个节点
    ListNode last = reverseN(head.next, n - 1);

    head.next.next = head;
    // 让反转之后的 head 节点和后面的节点连起来
    head.next = successor;
    return last;
}

为什么要加successor呢?

现在 head 节点在递归反转之后不一定是最后一个节点了,所以要记录后驱 successor(第 n + 1 个节点),反转之后将 head 连接上。

反转链表的一部分

ListNode reverseBetween(ListNode head, int m, int n) {
    // base case
    if (m == 1) {
        return reverseN(head, n);
    }
    // 前进到反转的起点触发 base case
    head.next = reverseBetween(head.next, m - 1, n - 1);
    return head;
}
原文地址:https://www.cnblogs.com/treasury/p/12751395.html