给你单链表的头指针 head
和两个整数 left
和 right
,其中 left <= right
。请你反转从位置 left
到位置 right
的链表节点,返回 反转后的链表 。
穿针引线
这个方法就不多说了,找到边界 在给的left和right中进行反转链表,再把两个边界和新反转好的链表穿起来就好。唯一要注意的就是边界问题
一次遍历「穿针引线」反转链表(头插法)
使用三个指针变量 pre、curr、next 来记录反转的过程中需要的变量,它们的意义如下:
curr:指向待反转区域的第一个节点 left;
next:永远指向 curr 的下一个节点,循环过程中,curr 变化以后 next 会变化;
pre:永远指向待反转区域的第一个节点 left 的前一个节点,在循环过程中不变。
操作步骤:
先将 curr 的下一个节点记录为 next;
执行操作 ①:把 curr 的下一个节点指向 next 的下一个节点;
执行操作 ②:把 next 的下一个节点指向 pre 的下一个节点;
执行操作 ③:把 pre 的下一个节点指向 next。
相当于在left和right范围内使用头插法,不断把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 dummy = new ListNode(0, head);
ListNode pre = dummy;
for(int i=1; i<left; i++) {
pre = pre.next;
}
ListNode cur = pre.next;
for(int i=0; i<right-left; i++) {
ListNode nex = cur.next;
cur.next = nex.next;
nex.next = pre.next;
pre.next = nex;
}
return dummy.next;
}
}
复杂度分析:
-
时间复杂度:O(N),其中 N 是链表总节点数。最多只遍历了链表一次,就完成了反转。
-
空间复杂度:O(1)。只使用到常数个变量。