目录
描述
将给出的链表中的节点每 k 个一组翻转,返回翻转后的链表
如果链表中的节点数不是 k 的倍数,将最后剩下的节点保持原样
你不能更改节点中的值,只能更改节点本身。
数据范围: 0≤n≤2000 , 1≤k≤2000 ,链表中每个元素都满足0≤val≤1000;要求空间复杂度 O(1),时间复杂度 O(n)
例如:
给定的链表是 1→2→3→4→5
对于k=2 , 你应该返回 2→1→4→3→5
对于 k=3 , 你应该返回3→2→1→4→5
示例1
输入:{1,2,3,4,5},2
返回值:{2,1,4,3,5}
示例2
输入:{},1
返回值:{}
题目分析
首先,我们要实现一个reverse函数反转一个区间之内的元素。在此之前我们再简化一下,在给定头节点的情况下对链表进行反转。
// 反转以 a 为头结点的链表
ListNode reverse(ListNode a) {
ListNode pre, cur, nxt;
pre = null; cur = a; nxt = a;
while (cur != null) {
nxt = cur.next;
// 逐个结点反转
cur.next = pre;
// 更新指针位置
pre = cur;
cur = nxt;
}
// 返回反转后的头结点
return pre;
}
反转以a为头结点的链表其实就是反转a到null之间的结点,那么反转a到b之间的结点就只需要吧null改为b是不是就可以实现了?下面给出反转a到b之间节点的代码:
/** 反转区间 [a, b) 的元素,注意是左闭右开 */
ListNode reverse(ListNode a, ListNode b) {
ListNode pre, cur, nxt;
pre = null; cur = a; nxt = a;
// while 终止的条件改一下就行了
while (cur != b) {
nxt = cur.next;
cur.next = pre;
pre = cur;
cur = nxt;
}
// 返回反转后的头结点
return pre;
}
现在我们迭代实现了反转部分链表的功能,那么只需要遍历种反转链表不就是可以了么,下面是完整代码:
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
auto node=head;
for (int i=0;i<k;i++) {
if (!node) return head;
node = node->next;
}
auto res = reverse(head, node); // 翻转长度是k的链表
head->next = reverseKGroup(node, k); // 递归处理下一个长度是k的链表
return res; //返回头指针
}
private:
//reverse函数实现反转a到b之间的结点
ListNode* reverse(ListNode* left, ListNode* right) {
auto pre=right;
while (left!=right) {
auto node=left->next;
left->next=pre;
pre = left;
left = node;
}
return pre;
}
};
时间复杂度:O(n)
空间复杂度:O(1) 没有使用额外空间
优缺点:时间复杂度低,但是思考过程难 不容易向到