LeetCode-92. 反转链表 II

题目来源

92. 反转链表 II

题目详情

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

示例 1:

输入: head = [1,2,3,4,5], left = 2, right = 4
输出: [1,4,3,2,5]

示例 2:

输入: head = [5], left = 1, right = 1
输出: [5]

提示:

  • 链表中节点数目为 n
  • 1 <= n <= 500
  • -500 <= Node.val <= 500
  • 1 <= left <= right <= n

进阶: 你可以使用一趟扫描完成反转吗?

相似题目

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

题解分析

解法一:迭代法

  1. 206. 反转链表题目类似,本题的核心还是在反转链表,只不过这里不是从头开始反转,而是从指定位置反转。
  2. 既然不是从头开始反转,那我们就找到开始反转链表的位置,接着调用反转链表的方法完成链表的反转。需要注意的是,为了标识需要反转的结束位置,我将right-left传入方法中,循环时不断自减k来标识反转的边界。
  3. 在循环中还需要做的是,需要将新的尾结点的next指针指向原先尾节点的next指针,这样可以避免再次遍历一次链表。
/**
 * 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 left, int right) {
        ListNode dumyNode = new ListNode(-1);
        dumyNode.next = head;
        ListNode now = dumyNode, pre = dumyNode;
        for(int i=0; i<left; i++){
            pre = now;
            now = now.next;
        }
        pre.next = reverse(now, right-left);
        return dumyNode.next;
    }

    private ListNode reverse(ListNode head, int k){
        ListNode pre = null;
        ListNode now = head;
        while(k >= 0){
            ListNode temp = now.next;
            now.next = pre;
            pre = now;
            now = temp;
            k--;
        }
        head.next = now;
        return pre;
    }
}

解法二:穿针引线-头插法

image

  1. 根据题意,我们需要反转从节点2开始的链表,所以我们可以知道,2节点一定是最后一个节点,而所谓的反转就是不断将后面的节点依次插入到2节点前面。
  2. 以上的思路也可以叫做头插法,就是将后面的节点插入到新链表的头节点中。
  3. 这种穿针引线方法的节点赋值的顺序十分重要,通过我们设置的两个指针p,q可以分别指向新子链表的前驱节点和新链表的最后一个节点。
  4. 在修改removed待移动节点的next指针时,并不是将next指针指向q,因为后续removed和q之间可能会新增其他节点。ps,因为这是头插法,这是十分容易出错的一个点。
/**
 * 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 left, int right) {
        ListNode dumyNode = new ListNode(-1);
        dumyNode.next = head;
        ListNode p = dumyNode, q = dumyNode.next;
        for(int i=0; i<left-1; i++){
            p = p.next;
            q = q.next;
        }
        for(int i=0; i<right-left; i++){
            ListNode removed = q.next;
            // 以下的顺序不能调乱
            q.next = removed.next;
            removed.next = p.next;
            p.next = removed;

        }
        return dumyNode.next;
    }
}

参考

Java-双指针-头插法

posted @ 2022-02-08 21:17  Garrett_Wale  阅读(345)  评论(0编辑  收藏  举报