LeetCode 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]

解题思路

可以根据分治法的解题思路将一个大问题分解成多个小问题(即每个长度为 k 的子链表),递归地解决这些小问题,然后将结果合并,最终解决原始的大问题。

具体步骤如下:

  1. 确定是否需要反转

    • 首先,检查链表是否为空或者链表中的节点数量是否少于 k。如果是,那么不需要进行任何反转,直接返回原始的头节点 head
  2. 确定反转区间

    • 使用两个指针 ab 遍历链表,确定需要反转的节点区间。a 指向区间的开始,b 指向区间的结束(不包括 b 本身)。通过遍历链表,找到第 k 个节点,如果找不到足够的节点,则不进行反转。
  3. 反转节点

    • 确定好需要反转的区间后,调用 reverse 函数来反转这个区间内的节点。reverse 函数通过改变节点的 next 指针来实现节点的反转,而不改变节点的值。
  4. 递归处理剩余链表

    • 反转完当前区间的节点后,将反转后的区间的下一个节点(即 a.next)连接到递归调用 reverseKGroup(b, k) 的结果上。这样,递归地处理剩余的链表,直到整个链表都被处理完毕。
  5. 连接反转后的链表

    • 递归结束后,每个长度为 k 的子链表都被反转,并且它们通过递归调用的结果连接起来,形成最终的反转链表。
  6. 返回结果

    • 最终,reverseKGroup 函数返回新的头节点,这个节点指向整个链表的第一个反转后的子链表的头节点。

代码

/**
 * 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) {
    if(head == null) return null;
    // 区间 [a, b) 包含 k 个待反转元素
    let a, b;
    a = b = head;
    for(let i = 0; i < k; i++) {
        // 不足 k 个,不需要反转
        if(b == null) return head;
        b = b.next;
    }
    // 反转前 k 个元素
    let newHead = reverse(a, b);
    // 递归反转后续链表并连接起来
    a.next = reverseKGroup(b, k);
    return newHead;
};
 
// 反转区间 [a, b) 的元素,左闭右开
var reverse = function(a, b) {
    let pre = null, cur = a;
    while(cur != b) {
        let next = cur.next;
        cur.next = pre;
        pre = cur;
        cur = next;
    }
    return pre;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值