一起学习LeetCode热题100道(31/100)

31.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

解析:
reverseKGroup 函数的目标是将链表中的节点每 k 个一组进行翻转,并返回翻转后的链表头节点。
1.初始化哑节点: 首先,创建一个哑节点(dummy node),它的 next 指针指向链表的原始头节点。哑节点的作用是方便处理链表的头部翻转情况,因为翻转后的头部可能不再是原始的头节点。

2.遍历链表: 使用一个循环来遍历链表。在每次循环中,我们都尝试翻转接下来的 k 个节点。

3.检查剩余节点数: 在翻转之前,我们需要检查从当前 head 开始的剩余节点数是否至少为 k。这是通过设置一个 tail 指针并向前移动 k 步来实现的。如果在移动过程中 tail 变为 null,则说明剩余节点不足 k 个,函数可以直接返回当前链表(因为剩余部分不需要翻转)。

4.翻转节点: 如果剩余节点数至少为 k,则调用 reverseList 函数翻转从 head 到 tail.next(不包括 tail.next)之间的节点。reverseList 函数返回翻转后的头节点(原 tail.next)和尾节点(原 head)。

5.连接翻转后的段和剩余部分: 将翻转后的段重新连接到链表的其余部分。具体来说,将 prev.next 指向翻转后的头节点(head 在翻转后变成了尾节点),并将翻转后的尾节点(原 head)的 next 指针指向剩余的链表部分(nextGroup)。

6.更新指针: 更新 prev 指针到翻转后的尾节点,以便下一次循环时可以正确处理。同时,更新 head 指针到剩余的链表部分(nextGroup),以便继续遍历。

7.重复过程: 重复上述过程,直到遍历完整个链表。

8.返回结果: 返回哑节点的 next 指针,它现在指向翻转后的链表头节点。

reverseList 函数用于翻转链表中的一段节点。
1.初始化指针: 接收要翻转的链表的头节点 head 和尾节点的下一个节点 tail.next(我们称之为 prev,因为在翻转后它将成为新的头节点)。

2.翻转节点: 使用一个循环来遍历要翻转的节点。在每次迭代中,保存当前节点的 next 指针(即下一个节点),然后将当前节点的 next 指针指向前一个节点(prev)。接着,将 prev 和 curr 指针都向前移动一个节点。

3.返回结果: 当遍历完所有要翻转的节点后,prev 指针将指向新的头节点,而原始的 head 节点将指向新的尾节点(因为它现在是最后一个被翻转的节点)。函数返回这两个节点。

var reverseKGroup = function(head, k) {
// 创建一个哑节点(dummy node),它的next指向链表的头节点  
    let dummy = new ListNode(0);  
    dummy.next = head;  
    let prev = dummy; // prev始终指向当前翻转段的前一个节点  
  
    while (head) {  
        // 检查剩余部分长度是否大于等于k  
        let tail = prev;  
        // 前进k-1步找到尾节点  
        for (let i = 0; i < k; i++) {  
            tail = tail.next;  
            if (!tail) {  
                // 剩余部分不足k个,直接返回结果  
                return dummy.next;  
            }  
        }  
  
        // 记录下一部分的头节点  
        let nextGroup = tail.next;  
  
        // 翻转当前段的k个节点  
        [head, tail] = reverseList(head, tail);  
  
        // 连接翻转后的段和下一部分  
        prev.next = head;  
        tail.next = nextGroup;  
  
        // 移动prev和head到下一部分的开始  
        prev = tail;  
        head = nextGroup;  
    }  
  
    return dummy.next;  
};
// 翻转链表中的一部分,返回翻转后的头尾节点  
function reverseList(head, tail) {  
    let prev = tail.next; // prev初始化为tail的下一个节点,翻转后将是新的头节点  
    let curr = head;  
  
    while (prev !== tail) {  
        let next = curr.next;  
        curr.next = prev;  
        prev = curr;  
        curr = next;  
    }  
  
    return [prev, head];  
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值