1. 题目来源
链接:92. 反转链表 II
题单:
-
- 链表、二叉树与一般树(前后指针/快慢指针/DFS/BFS/直径/LCA)
- §1.4 反转链表
2. 题目解析
反转链表的一个小变种,抓住核心即可。
反转链表的核心在于 a, b, c 起始位置及终止位置。
- 起始位置:a 在反转的前一个,b 在反转的开头
- 终止位置:a 在反转的末尾,b 在反转末尾的下一个位置,可能为 null。
思路:
- 待反转链表的区间 [l, r],那么我们需要将 l->next = r->next,让 l-1->next=r
- 那么针对 r->next 在此恰好就是等于 b 的所处位置
- 针对 l-1 其实就是 从头节点开始跳 left-1 个节点所处位置,也就是 a 节点的初始位置。
坑点&技巧:
- 因为这里涉及到 l-1 这个节点,即当 left=1 的时候就又可能出现头节点改变的情况。
- 常用做法就是在这里建立 dummy 节点作为虚拟头节点。dummy->next 一直指向真正的头节点即可。
- 注意 l-1->next->next = b 应该在 l-1->next=a 之前。若调换位置,则 l-1->next->next= a->next = b 意义将发生改变。即改变的时候,应该从后向前发生改变,这样才互不影响。
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( 1 ) O(1) O(1)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int left, int right) {
auto dummy = new ListNode(-1, head);
auto cur = dummy;
for (int i = 0; i < left - 1; i ++ ) cur = cur->next;
auto a = cur, b = cur->next;
for (int i = left; i <= right; i ++ ) {
auto c = b->next;
b->next = a;
a = b;
b = c;
}
cur->next->next = b;
cur->next = a;
return dummy->next;
}
};