题目
给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 .反转链表II
输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]
解题思路
- 链表长度为N,left和right满足 1<= left <= right <= N,如果不满足条件,直接返回头指针
- 找到left - 1位置的节点Lpre和right + 1位置的节点 Rpos,Lpre和Rpos就是要反转链表的前驱节点和后继节点,此时只要将要反转的区域反转完成之后,在拼接正确的位置即可
- 如果当Lpre为空时,表示反转的范围包含头结点,反转之后返回反转部分的第一个节点,反之直接返回head
/**
* 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) {
// 查找到left和right的前驱lpre和后继节点rpos
// 查找到之后,反转就是lpre + 1 到 rpos - 1 范围内开始反转
// 如果lpre为空时,说明head包含在反转内,需要返回新头,不为空,直接返回head
int len = 0;
ListNode *node1 = head, *lpre = nullptr, *rpos = nullptr;
while (node1) {
len++;
// 判断当前的长度len是否为前驱后继的位置,如果位置正确赋值
lpre = len == left - 1 ? node1 : lpre;
rpos = len == right + 1 ? node1 : rpos;
node1 = node1->next;
}
if (left >= right || left < 1 || right > len)
return head;
node1 = lpre == nullptr ? head : lpre->next;
ListNode* node2 = node1->next;
// 反转位置的开头连接反转位置的结尾第一个节点
node1->next = rpos;
ListNode* next = nullptr;
while(node2 != rpos)
{
next = node2->next;
node2->next = node1;
node1 = node2;
node2 = next;
}
// 判断lpre是否为空
// 不为空时,说明反转的区域 1 < left
if(lpre)
{
lpre->next = node1;
return head;
}
return node1;
}
};