解题思路
将链表分为三部分:[0, m)
、[m, n]
、(n, L]
,其中 L
为链表长度。
第一步:使用虚拟头节点 dummy
,用于将 head
也能参与操作;
第二步:找到第 m-1
节点(firstHalfEnd
),用于连接反转后的第二部分链表;
第三步:遍历[m, n],进行链表反转。注意在反转前要保存待反转链表区间的第一个节点,用于连接第三部分链表;
第四步:
firstHalfEnd.next = pre; // 此时的 pre 指向反转后的链表区间的第一个节点
secondHalfEnd.next = cur; // 此时的 cur 指向第三部分链表的第一个节点,也就是第 n+1 个节点
代码
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
* public ListNode(int x) { val = x; }
* }
*/
public class Solution {
public ListNode ReverseBetween(ListNode head, int m, int n) {
if(head == null || head.next == null || m == n) {
return head;
}
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode cur = head;
ListNode firstHalfEnd = dummy;
for(int i = 1; i < m; i++) {
firstHalfEnd = cur;
cur = cur.next;
}
// 反转链表区间
ListNode pre = null, secondHalfEnd = cur;
for(int i = m; i <= n; i++) {
var nextTmp = cur.next;
cur.next = pre;
pre = cur;
cur = nextTmp;
}
// 此时的 cur 指向第三部分的头节点
firstHalfEnd.next = pre;
secondHalfEnd.next = cur;
return dummy.next;
}
}
复杂度分析
- 时间复杂度:(O(n)),其中 (n) 是链表的长度。一次遍历,因此时间复杂度为 (O(n))。
- 空间复杂度:(O(1))