力扣25.K个一组翻转链表(JavaScript版)

58 阅读2分钟

题目描述:

给你链表的头节点 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 <= 5000
  • 0 <= Node.val <= 1000

解题过程:

  1. 首先求出链表长度,小于k则无需翻转
  2. 需要创建虚拟头节点,将虚拟头节点的下一个节点指向实际的head
  3. 翻转链表,先用变量temp记录当前节点(cur)的next,再将当前节点(cur)指向上一个节点(prev),将prev指针移动到cur,将cur指针向后移动到temp
  4. 连接翻转后的链表,同时将链表剩余长度减去k,head.next指向翻转部分的最后一个节点,原链表需要翻转部分的第一个节点此时为最后一个节点,需要指向当前节点(遍历结束时cur指针来到了翻转部分的后一个节点,也就是下一次翻转的头节点)
  5. 需要记录翻转的头节点(个人觉得用一个变量表示比较清晰),翻转之后成为尾节点,下一个节点即为下一次翻转的头节点
  6. 最后返回头节点即可(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;
};