• LeetCode 725 分割链表


    给你一个头结点为 head 的单链表和一个整数 k ,请你设计一个算法将链表分隔为 k 个连续的部分。

    每部分的长度应该尽可能的相等:任意两部分的长度差距不能超过 1 。这可能会导致有些部分为 null 。

    k 个部分应该按照在链表中出现的顺序排列,并且排在前面的部分的长度应该大于或等于排在后面的长度。

    返回一个由上述 k 部分组成的数组。

     

    示例 1:

    输入:head = [1,2,3], k = 5
    输出:[[1],[2],[3],[],[]]
    解释:
    第一个元素 output[0] 为 output[0].val = 1 ,output[0].next = null 。
    最后一个元素 output[4] 为 null ,但它作为 ListNode 的字符串表示是 [] 。
    

    示例 2:

    输入:head = [1,2,3,4,5,6,7,8,9,10], k = 3
    输出:[[1,2,3,4],[5,6,7],[8,9,10]]
    解释:
    输入被分成了几个连续的部分,并且每部分的长度相差不超过 1 。前面部分的长度大于等于后面部分的长度。
    

    提示:

    • 链表中节点的数目在范围 [0, 1000]
    • 0 <= Node.val <= 1000
    • 1 <= k <= 50
    均匀分割:

    先对链表进行一次扫描,得到总长度cnt , 再将链表划分成k分,直接在原链表上进行划分,只需要在合适的分割位置,将节点的next指针置为空即可

    public static ListNode[] splitListToParts(ListNode head, int k) {
        // 即使head 为null,也要分割成k个null
        if (k == 0) return new ListNode[]{};
        // 链表的总长度
        int lengths = 0;
        ListNode listNode = head;
        while (listNode != null) {
            lengths++;
            listNode = listNode.next;
        }
    
        ListNode[] listNodes = new ListNode[k];
        // 重新指向链表首节点
        ListNode p = head;
        // 分割后每部分的最大长度
        int partLength = 0;
        // 统计已分割部分的总长度
        int splitedLength = 0;
        for (int i = 0; i < k; i++) {
            // 重新计算剩余部分进行分割的长度 = 链表剩余长度 / 可以分割的若干部分
            // 链表剩余长度 = (链表总长度-已分割部分的长度)
            // 链表剩余长度+ (可分割成多少段-1) 是因为输入被分成了几个连续的部分,并且每部分的长度相差不超过 1 ,前面部分的长度大于等于后面部分的长度
            partLength = (lengths - splitedLength + k - i - 1) / (k - i);
            // 统计已分割部分的总长度
            splitedLength += partLength;
            if (p != null) {
                // 指向新的连续部分的开始节点,使用这个指针是为了后续进行分割时将一段连续部分的尾指针和其下一个节点进行分割
                ListNode q = p;
                listNodes[i] = q;
                // 需要指向下一个节点,
                p = p.next;
                // 逐渐遍历节点,使其满足条件的分割成一个连续的部分
                for (int j = 0; j < partLength - 1 && p != null; j++) {
                    q = q.next;
                    p = p.next;
                }
                q.next = null;
            } else {
                break;
            }
        }
        return listNodes;
    }
    

    每个部分的链表长度计算方式:剩余未处理部分的链表长度分割成待分配份数,

    partLength = (lengths - splitedLength + k - i - 1) / (k - i);

    partLength是当前部分可分配的节点个数;

    lengths - splitedLength是剩余未处理部分的链表长度

    k-i-1 是为了保证当前部分的链表长度比后面部分的链表长

    k-i 是待分配份数;

    也可采取另一种计算方式:

    先获取理论上最小分割长度

    per=lengths / k;

    分配给per长度的节点后,再判断是否还需要再分配一个节点,判断方式是

    当「已处理的链表长度 + 剩余待分配份数 * per < cnt」,再分配一个单位长度

  • 相关阅读:
    字符串算法—正则表达式
    字符串算法—字符串搜索
    字符串算法—字典树
    字符串算法—字符串排序(下篇)
    字符串算法—字符串排序(上篇)
    图表算法—最短路径
    基本算法——前缀和与差分
    图论——图的表示
    基本算法——康托展开与逆康托展开
    基本算法——离散化
  • 原文地址:https://www.cnblogs.com/fyusac/p/15319809.html
Copyright © 2020-2023  润新知