题目链接
题目描述
给你单链表的头指针 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
解题思路
方法一:双指针
记录左链表和右链表,反转中间的链表,然后链接左右链表
我们还需要记录left的前一个节点,和right的后一个节点。如图所示:
/**
* 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) {
if(head==nullptr||left>=right)
return head;
ListNode* hair = new ListNode();
hair->next = head;
// 记录head前的结点
ListNode* prev = hair;
// 记录当前位置
int pos = 1;
// 找到开始反转位置
// 反转位置开始结点为head
while(pos<left&&head!=nullptr){
prev = head;
head = head->next;
++pos;
}
// 如果第一个反转结点为空,则不需要反转
if(head==nullptr)
return hair->next;
// 记录开始反转结点左边的第一个结点
ListNode* pleft = prev;
// 记录第一个反转结点,第一个反转结点为反转链表的尾结点
ListNode* pright = head;
// 以此反转结点,直至反转完成或者到达链表结尾
while(pos<=right&&head!=nullptr){
pos++;
ListNode* tmp = head->next;
head->next = prev;
prev = head;
head = tmp;
}
// 将左边链表链接上反转最后一个结点
pleft->next = prev;
// 将反转后的结点链接到右边链表
// head为右边链表的头结点
pright->next = head;
// 返回头结点
return hair->next;
}
};
- 时间复杂度 O(n)
-
方法二:反转链表(头插法)
在需要反转的区间里,每遍历到一个节点,让这个新节点来到反转部分的起始位置。下面的图展示了整个流程。
class Solution { public: ListNode *reverseBetween(ListNode *head, int left, int right) { // 设置 dummyNode 是这一类问题的一般做法 ListNode *dummyNode = new ListNode(-1); dummyNode->next = head; ListNode *pre = dummyNode; for (int i = 0; i < left - 1; i++) { pre = pre->next; } ListNode *cur = pre->next; ListNode *next; for (int i = 0; i < right - left; i++) { next = cur->next; cur->next = next->next; next->next = pre->next; pre->next = next; } return dummyNode->next; } };
时间复杂度 O(n)
- 空间复杂度 O(1)