【Leetcode 每日一题】25. K 个一组翻转链表

发布于:2024-11-29 ⋅ 阅读:(14) ⋅ 点赞:(0)

25. 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个节点,接着将反转后的节点组重新连接到原链表中,最后返回新链表的头节点。这个过程需要在每次反转后更新指针,以确保链表的连续性和正确性。

代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
// 这是链表节点的结构体定义,包含一个整型值和一个指向下一个节点的指针。
// 提供了三个构造函数,分别用于创建默认节点、带有值的节点和带有值及下一个节点的节点。

class Solution {
public:
    // 定义一个pair,用于存储反转链表的头尾节点
    pair<ListNode*, ListNode*> myReverse(ListNode* head, ListNode* tail){
        ListNode* prev = tail->next; // 初始化prev为tail的下一个节点,即反转后的第一个节点
        ListNode* p = head; // 初始化p为当前处理的节点,从头节点开始
        while (prev != tail){ // 遍历链表直到prev等于tail,即到达需要反转的链表的末尾
            ListNode* nex = p->next; // 保存p的下一个节点
            p->next = prev; // 反转p的next指针,指向prev
            prev = p; // 移动prev到p的位置
            p = nex; // 移动p到下一个节点
        }
        return {tail,head}; // 返回反转后的链表头尾节点
    }

    ListNode* reverseKGroup(ListNode* head, int k) {
        ListNode* hair = new ListNode(0); // 创建一个虚拟头节点,方便处理原链表头
        hair->next = head; // 虚拟头节点的next指向原链表头
        ListNode* pre = hair; // 初始化pre为虚拟头节点,用于追踪反转组的前一个节点

        while(head){ // 遍历链表直到到达末尾
            ListNode* tail = pre; // 初始化tail为pre,即当前组的起始节点
            for(int i=0;i<k;++i){ // 检查是否有足够的节点进行反转
                tail = tail->next; // 移动tail指针,寻找当前组的尾节点
                if(!tail){ // 如果tail为空,说明没有足够的节点进行反转
                    return hair->next; // 返回原链表头
                }
            }

            ListNode* nex = tail->next; // 保存tail的下一个节点,即下一组的头节点
            tie(head,tail) = myReverse(head, tail); // 调用myReverse反转当前组
            pre->next = head; // 将反转后的头节点连接到pre的后面
            tail->next = nex; // 将反转后的尾节点连接到下一组的头节点
            pre = tail; // 更新pre为当前组的尾节点,即下一组的起始节点
            head = tail->next; // 更新head为下一组的头节点
        }
        return hair->next; // 返回新链表的头节点
    }
};