题目描述:
给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。
k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k的整数倍,那么请将最后剩余的节点保持原有顺序。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
示例 1:
输入: head = [1,2,3,4,5], k = 2
输出: [2,1,4,3,5]
示例 2:
输入: head = [1,2,3,4,5], k = 3
输出: [3,2,1,4,5]
提示:
- 链表中的节点数目为
n 1 <= k <= n <= 50000 <= Node.val <= 1000
解题过程:
- 首先求出链表长度,小于k则无需翻转
- 需要创建虚拟头节点,将虚拟头节点的下一个节点指向实际的
head - 翻转链表,先用变量
temp记录当前节点(cur)的next,再将当前节点(cur)指向上一个节点(prev),将prev指针移动到cur,将cur指针向后移动到temp - 连接翻转后的链表,同时将链表剩余长度减去k,
head.next指向翻转部分的最后一个节点,原链表需要翻转部分的第一个节点此时为最后一个节点,需要指向当前节点(遍历结束时cur指针来到了翻转部分的后一个节点,也就是下一次翻转的头节点) - 需要记录翻转的头节点(个人觉得用一个变量表示比较清晰),翻转之后成为尾节点,下一个节点即为下一次翻转的头节点
- 最后返回头节点即可(
dummy.next)
复杂度
- 时间复杂度: O(n)
- 空间复杂度: O(1)
完整代码及注释
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val === undefined ? 0 : val);
* this.next = (next === undefined ? null : next);
* }
*/
/**
* @param {ListNode} head
* @param {number} k
* @return {ListNode}
*/
var reverseKGroup = function(head, k) {
// 1. 先统计链表的长度
let n = 0;
let node = head;
while (node) {
n += 1;
node = node.next;
}
// 2. 创建虚拟头节点,方便操作
let dummy = new ListNode(0, head);
let p0 = dummy; // p0指向虚拟头节点
let prev = null, cur = p0.next, temp = null;
// 3. 进行每 k个节点的反转
while (n >= k) {
//保存当前翻转部分的起始节点
let start=cur
// 反转 k个节点
for (let i = 0; i < k; i++) {
temp = cur.next;
cur.next = prev;
prev = cur;
cur = temp;
}
// 反转完成后,将p0.next指向新的头节点
p0.next = prev; // p0.next指向反转后的部分的头节点
start.next = cur; // 原反转部分的尾节点指向cur,即下一组的头节点
// 4. 更新p0为反转部分的尾节点
p0 = start;
// 减少剩余的节点数量
n -= k;
}
// 5. 返回虚拟头节点的next,即反转后的链表头
return dummy.next;
};