【LeetCode热题100道笔记】K 个一组翻转链表

题目描述

给你链表的头节点 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
进阶:你可以设计一个只用 O(1) 额外内存空间的算法解决此问题吗?

思考

通过哨兵节点+快慢指针实现每k个节点一组的翻转:先用快指针探测当前位置后是否有k个节点可翻转(快指针超前慢指针k-1步),若存在则翻转从慢指针开始的k个节点,将翻转后的子链表连接到结果链表中,再更新指针继续处理下一组;若不足k个节点则直接拼接剩余部分,最终返回哨兵节点的后继即为结果。

算法过程

  1. 初始化:创建哨兵节点guard(简化头节点处理),定义slow(当前组起始指针)、fast(探测指针)初始均指向headp(结果链表尾指针)初始指向guard
  2. 循环处理各组
    • 探测k个节点:快指针fast向前移动k-1步,若移动后fastnull(不足k个节点),则跳出循环。
    • 翻转当前组:调用reverseLink函数翻转从slow开始的k个节点,返回翻转后的子链表头节点。
    • 连接翻转后的子链表:将p.next指向翻转后的头节点,更新p为当前组原头节点(翻转后变为尾节点)。
    • 更新指针到下一组slowfast均移动到当前组尾节点的下一个节点(下一组起始位置)。
  3. 处理剩余节点:若剩余节点不足k个,p会自然连接剩余部分(无需额外操作)。
  4. 返回结果:返回guard.next(哨兵节点的后继即为最终链表头节点)。

辅助函数reverseLink说明
输入链表头节点head和翻转长度k,翻转这k个节点,返回翻转后的头节点,同时让原头节点(翻转后为尾节点)的next指向未翻转的剩余部分,确保链表连续。

该算法时间复杂度为O(n)(n为链表长度,每个节点最多被访问2次),空间复杂度为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) {
  let slow = head, fast = head;
  let guard = new ListNode();
  let p = guard;
  while (fast) {
    for (let i = 0; i < k-1; i++) {
        if (fast) {
            fast = fast.next;
        } else {
            break;
        }
    }
    if (!fast) {
        break;
    }
    p.next = reverseLink(slow, k);
    p = slow;
    slow = slow.next;
    fast = slow;
  }

  return guard.next;
};

function reverseLink(head, k) {
    let p = head, q = p.next;
    while (k > 1) {
        let tmp = q.next;
        q.next = p;
        head.next = tmp;
        p = q;
        q = tmp;
        k--;
    }
    return p;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值