题目链接
题目描述
给你单链表的头指针 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 <= 5001 <= 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;// 找到开始反转位置// 反转位置开始结点为headwhile(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)
