反转单链表LeetCode 206. 反转链表 92. 反转链表 II

欢迎来到茶色岛独家岛屿,本期将为大家揭晓LeetCode 206. 反转链表  92. 反转链表 II,做好准备了么,那么开始吧。

// 单链表节点的结构
public class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}

一、递归反转整个链表

206. 反转链表

一、力扣示例

206. 反转链表 - 力扣(LeetCode)https://leetcode.cn/problems/reverse-linked-list/

二、解决办法

对于递归算法,最重要的就是明确递归函数的定义。具体来说,我们的 reverse 函数定义是这样的:

输入一个节点 head,将「以 head 为起点」的链表反转,并返回反转之后的头结点。并且根据函数定义,reverse 函数会返回反转之后的头结点,我们用变量 last 接收了。

明白了函数的定义,再来看这个问题。

反转单链表LeetCode 206. 反转链表 92. 反转链表 II_第1张图片

三、代码实现

// 定义:输入一个单链表头结点,将该链表反转,返回新的头结点
ListNode reverse(ListNode head) {
    if (head == null || head.next == null) {
        return head;
    }
    ListNode last = reverse(head.next);
    head.next.next = head;
    head.next = null;
    return last;
}

二、反转链表前 N 个节点

解决办法

解决思路和反转整个链表差不多,只要稍加修改即可:

具体的区别:

1、base case 变为 n == 1,反转一个元素,就是它本身,同时要记录后驱节点

2、刚才我们直接把 head.next 设置为 null,因为整个链表反转后原来的 head 变成了整个链表的最后一个节点。但现在 head 节点在递归反转之后不一定是最后一个节点了,所以要记录后驱 successor(第 n + 1 个节点),反转之后将 head 连接上。

反转单链表LeetCode 206. 反转链表 92. 反转链表 II_第2张图片

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;
}

三、反转链表的一部分

 92. 反转链表 II

一、力扣示例

92. 反转链表 II - 力扣(LeetCode)https://leetcode.cn/problems/reverse-linked-list-ii/

二、解决办法 

现在解决我们最开始提出的问题,给一个索引区间 [m, n](索引从 1 开始),仅仅反转区间中的链表元素。

首先,如果 m == 1,就相当于反转链表开头的 n 个元素嘛,也就是我们刚才实现的功能:

ListNode reverseBetween(ListNode head, int m, int n) {
    // base case
    if (m == 1) {
        // 相当于反转前 n 个元素
        return reverseN(head, n);
    }
}

如果 m != 1 怎么办?如果我们把 head 的索引视为 1,那么我们是想从第 m 个元素开始反转对吧;如果把 head.next 的索引视为 1 呢?那么相对于 head.next,反转的区间应该是从第 m - 1 个元素开始的;那么对于 head.next.next 呢……

区别于迭代思想,这就是递归思想,所以我们可以完成代码:

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;
}

 三、代码实现

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public 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;

       
    }
    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;
    }
    

}

反转单链表LeetCode 206. 反转链表 92. 反转链表 II_第3张图片

反转单链表LeetCode 206. 反转链表 92. 反转链表 II_第4张图片

你可能感兴趣的:(LeetCode,链表,算法,数据结构)