题目 LeetCode 92
给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。
/**
* 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) {
}
}
示例 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
分析
头插法
方法一的缺点是: 如果 left 和 right 的区域很大,恰好是链表的头节点和尾节点时,找到left 和 right 需
要遍历一次,反转它们之间的链表还需要遍历一次,虽然总的时间复杂度为 O(N),但遍历了链表 2次,可
不可以只遍历一次呢? 答案是可以的。我们依然画图进行说明,我们仍然以头插法的序列为例进行说明。
可以参考我画的,你也可以自己动手画画:
1-6中,反转3-5区间的数字
穿针引线法
我们可以这么做: 先确定好需要反转的部分,也就是下图的 eft 到 right 之间,然后再将三段链表拼接起
来。这种方式类似裁缝一样,找准位置减下来,再缝回去。这样问题就变成了如何标记下图四个位置,以
及如何反转left到right之间的链表。
可以参考我画的,你也可以自己动手画画:
1-6中,反转2-5区间的数字
代码
头插法
class Solution {
public ListNode reverseBetween(ListNode head, int left, int right) {
ListNode dummyNode = new ListNode(0);
dummyNode.next = head;
ListNode prev = dummyNode;
for (int i = 0; i < left - 1; i++){
prev = prev.next;
}
ListNode curr = prev.next;
ListNode next;
for (int i = 0; i < right - left; i++){
next = curr.next;
curr.next = next.next;
next.next = prev.next;
prev.next = next;
}
return dummyNode.next;
}
}
穿针引线法
class Solution {
public ListNode reverseBetween(ListNode head, int left, int right) {
//使用虚拟节点,避免复杂分类讨论
ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode pre = dummy;
//for循环,让虚拟节点走到left节点的前一个
for (int i = 0; i < left - 1; i++){
pre = pre.next;
}
//从pre再走到right - left + 1步,来到right结点
ListNode rightNode = pre;
for (int i = 0; i < right - left + 1; i++){
rightNode = rightNode.next;
}
//切出一个子链表
ListNode leftNode = pre.next;
ListNode succ = rightNode.next;
rightNode.next = null;
//反转链表子区间
reverse(leftNode);
//接回原来的链表
pre.next = rightNode;
leftNode.next = succ;
return dummy.next;
}
private void reverse(ListNode head){
ListNode pre = null;
ListNode cur = head;
while (cur != null){
ListNode next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
}
}