力扣92_反转链表II

题目描述
给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回反转后的链表 。

示例:
在这里插入图片描述
算法思想

方法一:递归
在上一篇文章 反转链表I 中,我们学会了反转一个完整的链表,在做本题之前,先思考一个容易一点的问题,如何反转一个链表的前N个节点?如图所示:
在这里插入图片描述
有没有发现与上一篇文章的区别,就在1这个节点上,上一篇文章是把这个节点指向了null,而这里是把1这个节点指向了4,也就是说,如果我们像上一篇文章一样递归,只需在递归到最后一个节点3的时候,存储一个指向4节点的指针successor,最后把1指向这个指针就可以了。
那么,这个successor怎么去找呢?
我们思考一种更一般的情况,假如反转的节点只有1个怎么办?

if (n == 1) { 
    // 记录第 n + 1 个节点
    successor = head.next;
    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;
}

ok,这个问题已经解决了,我们再来看看今天的这道题目,反转从位置 left 到位置 right 的链表节点,如果left==1,不就是我上面的这种情况了吗,反转前right个节点。

if(left == 1)
	reverseN(ListNode head, int right);

如果left != 1呢?如果我们把head的索引视为1,那么我们想从第m个元素开始反转,如果把head.first视为1呢,那么就从m-1个元素开始反转,如果把head.first.first视为1呢…
这就构成了递归

ListNode reverseBetween(ListNode head, int left, int right){
	if(left == 1)
		return reverseN(ListNode head, int right);
	head.first = reverseBetween(head.next, left - 1, right - 1);
	return head;
}

复杂度分析
较难,以后再更。

方法二:穿针引线
同样借助 反转链表I 里面的方法,在此方法上做部分改进。
先分析与上个题目的区别:
不就是前后多个结点嘛,要反转的区间是[left, right],那么我们把left-1和right+1记下来,中间当作一整个一整个链表反转,完事后穿针引线不就可以了嘛
在这里插入图片描述

class Solution {
    public ListNode reverseBetween(ListNode head, int left, int right) {
        // 使用虚拟头节点避免复杂的分类讨论
        ListNode dummyNode = new ListNode(-1);
        dummyNode.next = head;

        ListNode pre = dummyNode;
        // 来到 left 节点的前一个节点
        for (int i = 0; i < left - 1; i++) {
            pre = pre.next;
        }

        // 来到 right 节点
        ListNode rightNode = pre;
        for (int i = 0; i < right - left + 1; i++) {
            rightNode = rightNode.next;
        }

        // 切断出一个子链表(截取链表)
        ListNode leftNode = pre.next;
        ListNode curr = rightNode.next;

        // 注意:切断链接
        pre.next = null;
        rightNode.next = null;

        // 反转链表的子区间
        reverseLinkedList(leftNode);

        // 接回到原来的链表中
        pre.next = rightNode;
        leftNode.next = curr;
        return dummyNode.next;
    }
}

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

相关推荐
©️2020 CSDN 皮肤主题: 1024 设计师:白松林 返回首页