【算法】725.分割链表--通俗讲解

一、题目是啥?一句话说清

给定一个链表和一个整数k,将链表分成k个连续部分,每部分长度尽可能相等(长度差不超过1),前面的部分长度要大于等于后面的部分。

示例:

  • 输入:head = 1,2,3,4,5,6,7,8,9,10, k = 3
  • 输出:\[1,2,3,4, 5,6,7, 8,9,10]

二、解题核心

先计算链表总长度,确定每部分的基本长度和需要额外加1的部分数量,然后遍历链表进行分割。

这就像把一列人分成k个小组,先数总人数,然后计算每组大概多少人,尽量让每组人数差不多,前面组的人可以比后面组多一个。

三、关键在哪里?(3个核心点)

想理解并解决这道题,必须抓住以下三个关键点:

1. 计算链表总长度

  • 是什么:遍历整个链表,统计节点总数。
  • 为什么重要:只有知道总长度,才能合理分配每部分的长度。

2. 确定每部分的长度

  • 是什么:每部分基本长度 = 总长度 / k,前 (总长度 % k) 个部分长度加1。
  • 为什么重要:这确保了任意两部分长度差不超过1,且前面部分长度≥后面部分。

3. 链表分割操作

  • 是什么:遍历链表,根据计算出的长度切断链表,形成k个独立部分。
  • 为什么重要:这是实际执行分割的关键步骤,需要正确操作指针。

四、看图理解流程(通俗理解版本)

假设链表:1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → 9 → 10,k = 3

  1. 计算总长度:10个节点
  2. 计算每部分长度
    • 基本长度 = 10 / 3 = 3
    • 余数 = 10 % 3 = 1
    • 所以前1部分长度=4,后2部分长度=3
  3. 分割链表
    • 第一部分:取4个节点 1,2,3,4
    • 第二部分:取3个节点 5,6,7
    • 第三部分:取3个节点 8,9,10
  4. 结果:三个链表 1→2→3→4, 5→6→7, 8→9→10

五、C++ 代码实现(附详细注释)

cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

// 链表节点定义
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:
    vector<ListNode*> splitListToParts(ListNode* head, int k) {
        // 第一步:计算链表总长度
        int length = 0;
        ListNode* current = head;
        while (current != nullptr) {
            length++;
            current = current->next;
        }
        
        // 第二步:计算每部分的基本长度和需要额外加1的部分数量
        int base_size = length / k;    // 每部分的基本长度
        int extra = length % k;        // 需要额外加1的部分数量
        
        vector<ListNode*> result(k, nullptr); // 初始化结果数组
        current = head;
        
        // 第三步:分割链表
        for (int i = 0; i < k && current != nullptr; i++) {
            result[i] = current; // 记录当前部分的头节点
            
            // 计算当前部分的长度
            int part_size = base_size + (i < extra ? 1 : 0);
            
            // 移动到当前部分的末尾
            for (int j = 1; j < part_size; j++) {
                current = current->next;
            }
            
            // 切断链表,形成独立部分
            if (current != nullptr) {
                ListNode* next_part = current->next;
                current->next = nullptr;
                current = next_part;
            }
        }
        
        return result;
    }
};

// 辅助函数:打印链表数组
void printParts(const vector<ListNode*>& parts) {
    for (int i = 0; i < parts.size(); i++) {
        cout << "Part " << i + 1 << ": ";
        ListNode* current = parts[i];
        while (current != nullptr) {
            cout << current->val << " ";
            current = current->next;
        }
        cout << endl;
    }
}

// 测试代码
int main() {
    // 构建示例链表:1->2->3->4->5->6->7->8->9->10
    ListNode* head = new ListNode(1);
    ListNode* current = head;
    for (int i = 2; i <= 10; i++) {
        current->next = new ListNode(i);
        current = current->next;
    }
    
    Solution solution;
    vector<ListNode*> result = solution.splitListToParts(head, 3);
    
    printParts(result);
    
    // 释放内存
    for (ListNode* part : result) {
        while (part != nullptr) {
            ListNode* temp = part;
            part = part->next;
            delete temp;
        }
    }
    
    return 0;
}

六、时间空间复杂度

  • 时间复杂度:O(n),其中n是链表长度。需要遍历链表两次:一次计算长度,一次进行分割。
  • 空间复杂度:O(k),用于存储结果数组,k是分割的部分数。

七、注意事项

  • 空链表处理:如果链表为空,返回k个nullptr。
  • k大于链表长度:当k > length时,前length部分是单个节点,后面的都是nullptr。
  • 指针操作:在切断链表时,要确保正确设置next指针为nullptr。
  • 边界检查:在移动指针时要检查current是否为nullptr,避免空指针异常。
  • 内存管理:在C++中,分割后的链表需要分别管理内存。
  • 结果顺序:结果数组中的链表必须保持原链表的顺序。
相关推荐
net3m3333 分钟前
一阶软件低通滤波器算法
人工智能·算法
乐观的山里娃1 小时前
【反八股 01】HashMap 的设计参数是怎么来的
面试
水木流年追梦1 小时前
大模型入门-大模型优化方法12-YaRN 长文本外推技术
人工智能·分布式·算法·正则表达式·prompt
J-Tony111 小时前
【JVM】三色标记法
java·jvm·算法
wengad1 小时前
机器学习实践理论基础|算法、模型和数据集
人工智能·算法·机器学习
嵌入式ZYXC2 小时前
第3篇:《面试题:I2C为什么要加上拉电阻?阻值怎么选?》
stm32·单片机·嵌入式硬件·面试·职场和发展
sbjdhjd2 小时前
面试(5)| 3.5 小时面试复盘第五弹:加班出差 + 客户响应 + 压力面全拆解
经验分享·程序人生·面试·职场和发展·开源·跳槽·求职招聘
梦梦代码精3 小时前
为什么这个开源的AI平台会火?有点东西。。。
人工智能·算法·机器学习·docker·开源
随意起个昵称3 小时前
线性dp-综合刷题1(Not Alone)
算法·动态规划
AI人工智能+电脑小能手3 小时前
【大白话说Java面试题 第102题】【并发篇】第2题:volatile 能否保证线程安全?
java·安全·面试