【面试高频题】反转链表

118 阅读2分钟

这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战

微软和谷歌的几个大佬组织了一个面试刷题群,可以加管理员VX:sxxzs3998(备注掘金),进群参与讨论和直播

1.题目

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

示例 1:

image.png

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

示例 2:

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

2.解析

反转 left 到 right 部分以后,再拼接起来。我们还需要记录 left 的前一个节点,和 right 的后一个节点。如图所示:

image.png

算法步骤:

  • 第 1 步:先将待反转的区域反转;
  • 第 2 步:把 pre 的 next 指针指向反转以后的链表头节点,把反转以后的链表的尾节点的 next 指针指向 succ。

image.png

具体思路见代码注释:

/**
 * 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 dummyNode = new ListNode(-1);
        dummyNode.next = head;
        // 第 1 步:从虚拟头节点走 left - 1 步,来到 left 节点的前一个节点
        ListNode pre = dummyNode;
        for(int i = 1; i < left; i++){
            pre = pre.next;
        }
        //left 节点的前一个节点
        ListNode listBegin = pre;
        pre = pre.next;
        //left节点
        ListNode subBegin = pre;
​
        // 第 2 步:从 pre 再走 right - left + 1 步,来到 right 节点
        for(int i = left; i < right; i++){
            pre = pre.next;
        }
        //right 节点
        ListNode subEnd = pre;
        pre = pre.next;
        //right 节点后的一个节点
        ListNode listEnd = pre;
​
        // 第 3 步:切断出一个子链表(截取链表)
        listBegin.next = null;
        subEnd.next = null;
​
        // 第 4 步:反转链表的子区间
        ListNode subPre = null;
        ListNode cur = subBegin;
        while(cur != null){
            ListNode curNext = cur.next;
            cur.next = subPre;
            subPre = cur;
            cur = curNext;
        }
        
        // 第 5 步:接回到原来的链表中
        subBegin.next = listEnd;
        listBegin.next = subEnd;
        //不能返回head,因为若输入为[3,5] left = 1, right = 2,
        //head在第一个位置,反转链表后为head在第二个位置,那么返回的结果就是[3]
        //返回dummyNode.next无论如何都是第一个节点,返回结果是[5,3]
        return dummyNode.next;  
    }
}

微软和谷歌的几个大佬组织了一个面试刷题群,可以加管理员VX:sxxzs3998(备注掘金),进群参与讨论和直播