给你单链表的头节点 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 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
进阶: 你可以使用一趟扫描完成反转吗?
先通过给定的左右界在链表中记录翻转区间的左右结点,和左结点的直接前驱和右结点的直接后继(无则置nullptr)
然后遍历翻转区间,记录当前结点的直接后继,然后将当前结点的直接后继变为直接前驱,如此不断遍历一遍即可(注意边界条件)
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int left, int right) {
ListNode* childHead = head;
ListNode* childTail = head;
ListNode* childPre = nullptr;
ListNode* childSuc = nullptr;
while(left > 1 || right > 1){
if(left == 2) childPre = childHead;
if(left > 1){
childHead = childHead->next;
left--;
}
if(right > 1){
childTail = childTail->next;
right--;
}
}
childSuc = childTail->next;
ListNode* pre = childSuc;
while(childHead != childSuc){
ListNode* nextNode = childHead->next;
childHead->next = pre;
pre = childHead;
childHead = nextNode;
}
if(childPre != nullptr) childPre->next = childTail;
else head = childTail;
return head;
}
};
当然也可以严格遍历一遍,只不过记录和翻转都在一次遍历内完成了
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int left, int right) {
ListNode* currentNode = head;
ListNode* pre = nullptr;
ListNode* intervalPre = nullptr;
ListNode* intervalSuc = nullptr;
ListNode* intervalHead = head;
ListNode* intervalTail = head;
bool isInInterval = false;
int currentIndex = 1;
while(currentNode != nullptr){
if(currentIndex == left){
isInInterval = true;
intervalHead = currentNode;
}
if(isInInterval){
ListNode* nextNode = currentNode->next;
currentNode->next = pre;
pre = currentNode;
currentNode = nextNode;
}else{
intervalPre = currentNode;
pre = currentNode;
currentNode = currentNode->next;
}
currentIndex++;
if(currentIndex == right) intervalTail = currentNode;
if(currentIndex > right) break;
}
if(intervalPre == nullptr) head = intervalTail;
else intervalPre->next = intervalTail;
intervalHead->next = currentNode;
return head;
}
};