“Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。”
一、题目描述
给你单链表的头指针 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
进阶: 你可以使用一趟扫描完成反转吗?
二、思路分析
之前写过一篇反转链表的简单题【前端面试常见算法题系列】206. 反转链表,如果你看了这篇题解,相信已经能够理解反转链表的具体流程了,那么再来做这道题会很简单,下面废话不多说,我们进入正题。
这道题要求返回只反转部分节点的链表,函数签名如下:
ListNode* reverseBetween(ListNode* head, int left, int right) {}
left 为反转的起点,right 为反转的终点。
思路其实很简单:
不需要反转的地方正常遍历,走到 left 的位置再将需要反转的部分传参给反转函数(并不是真的传递部分链表,而是传递部分链表的起止位置以及反转部分的第一个节点),而这里的反转函数几乎跟上面那篇题解的反转思路一致,但有一个点需要特别注意:反转后最后的指针不是指向 nullptr 了,而是指向需要反转的部分链表的后一个元素。
-
我们比较常用的链表遍历方式是迭代遍历,那如果是递归遍历呢,再加个难度:遍历到指定位置进行反转。(于是我想啊想啊,终于知道了)不就是递归吗,将当前链表节点的下一个节点传递给递归函数,那么就这个递归函数而言,里面的
head其实不再是刚开始的那个节点了,而是第二个节点,再递归,递归函数里的head就变成第三个节点了,以此类推... 这样就实现了递归遍历。 -
很好,递归遍历的问题解决了,那么又有一个新问题了,因为是原链表修改,那最后怎么返回头结点呢?其实这个问题不用担心,我们并没有
head = head -> next,因此头结点还是那个头结点。 -
好极了,返回了头结点,又进行反转了,接下来就剩下最后的链表指向了。假设链表需要反转的部分是中间部位,我们将链表的前面部分设为
1、反转部分设为2、后面的部分设置为3(这里是为了方便讲解设立的理想情况)那么只要1部分的最后一个节点指向2部分的最后一个节点、2部分的第一个节点指向3部分的第一个节点,那么就大功告成了。(有没有什么思路呢)
- 递归遍历的时候会一直走到反转函数,而反转函数又会继续递归,那么只要在反转的时候保存
2部分的第一个节点,等到反转完毕就会return,也就是返回了反转后的头结点,因此在递归遍历时head -> next指向递归函数的返回值皆可; - 接下来将
2部分反转后的最后一个节点指向3部分的第一个节点就好了,只要在遍历到2部分的最后一个节点时,记录它的下一个节点也就是3部分的第一个节点(假设为sign),就可以操作了,其实也只是在上面那篇题解的反转函数中ans = sign即可。
至此,这道题就到这里了,如果我讲的不明白,可以结合代码和上面的思路,自己按照示例 debug 一下应该就可以了,如果没能帮大家搞清楚,还请见谅!
三、AC 代码
/**
* 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* successor = nullptr;
ListNode* reverse(ListNode* head, int n) {
if (n == 1) {
successor = head -> next;
return head;
}
ListNode* last = reverse(head -> next, n - 1);
head -> next -> next = head;
head -> next = successor;
return last;
}
ListNode* reverseBetween(ListNode* head, int left, int right) {
if (left == 1) {
return reverse(head, right);
}
head -> next = reverseBetween(head -> next, left - 1, right - 1);
return head;
}
};