zoukankan      html  css  js  c++  java
  • 725. Split Linked List in Parts

    ▶ 将一个单链表拆分为长度尽量接近的 k 段

    ● 自己的代码,12 ms

    ■ 记链表长度为 count,目标段数为 k,quo = count / k,mod = count % k,part = mod * (quo + 1)

    ■ 前半截(长半截)共有 mod 组,每组 quo + 1 个元素,共 mod * (quo + 1) 个元素,这是 part 的由来;后半截(长半截)共有 k - mod 组,每组 quo 个元素,共 quo * (k - mod) 个元素

    ■ 当 i < part 时,第 i 元素处于前半截,组号 s = i / (quo + 1),该组最后一个元素下标为 t = (quo + 1) * (s + 1) - 1,即满足 (t + 1) % (quo + 1) == 0

    ■ 当 i >= part 时,第 i 元素处于后半截,组号 s = (i - part) / quo + mod = (i - mod) / quo,该组最后一个元素下标为 t = (s + 1) * quo + mod - 1 (前面所有组的元素个数,注意偏移量 mod),即满足 (t + 1 - mod) % quo == 0

     1 class Solution
     2 {
     3 public:
     4     vector<ListNode*> splitListToParts(ListNode* root, int k)
     5     {
     6         vector<ListNode *> table(k, nullptr);
     7         if (root == nullptr)
     8             return table;
     9         int count, i;
    10         ListNode *p, *q;        
    11         for (p = root, count = 1; p->next != nullptr; p = p->next, count++);// 计算结点数        
    12         const int quo = count / k, mod = count % k, mod * (quo + 1);
    13         for (p = table[0] = root, i = 0; p != nullptr && p->next != nullptr; i++)
    14         {
    15             if (i < part && !((i + 1) % (quo + 1)))// p 指向了前半截某组的末尾结点
    16             {                                                 
    17                 q = p->next, p->next = nullptr, p = q;
    18                 table[(i + 1) / (quo + 1)] = q;       // 注意此时是在table 中挂上 q 指向的结点,相当于第 i + 1 个结点
    19             }
    20             else if (i >= part && !((i + 1 - mod) % quo))// p 指向了后半截某组的末尾结点
    21             {                
    22                 q = p->next, p->next = nullptr, p = q;
    23                 table[(i + 1 - mod) / quo] = q;
    24             }
    25             else            
    26                 p = p->next;
    27         }
    28         return table;
    29     }
    30 };

    ● 大佬的代码,11 ms,使用简单的判断 idx < remainder 来确认切分位置

     1 class Solution
     2 {
     3 public:
     4     vector<ListNode*> splitListToParts(ListNode* root, int k)
     5     {
     6         if (k == 1)
     7             return vector<ListNode*>{ root };
     8         vector<ListNode*> res(k, nullptr);
     9         ListNode *temp;
    10         int len, idx, tmp;
    11         for (len = 0, temp = root; temp != nullptr; len++, temp = temp->next);
    12         const int per_len = len / k, remainder = len % k;
    13 
    14         for (idx = 0; idx < k; )
    15         {
    16             tmp = per_len + (idx < remainder ? 1 : 0);
    17             if (tmp == 0)
    18             {
    19                 res[idx++] = nullptr;
    20                 continue;
    21             }
    22             for (res[idx++] = root; tmp != 1; root = root->next, tmp--);
    23             temp = root->next, root->next = nullptr, root = temp;
    24         }
    25         
    26         return res;
    27     }
    28 };

    ● 大佬的方法,11 ms,号称不需要知道链表的长度。每次指针 slow 移动一格,指针 fast 移动 k 格,直到 fast 抵达链表尾部,这时 slow 大约移动了 n / k 格,即为分界点。实际上 fast 在整个过程中移动了 O(n2) 的次数,还不如提前一趟遍历计算链表的长度

     1 class Solution
     2 {
     3 public :
     4     vector<ListNode *> splitListToParts(ListNode *root, int k)
     5     {
     6         vector<ListNode *> res(k, nullptr);
     7         ListNode *fast, *slow;
     8         int i, step;
     9         for (i = 0; i < k; i++)
    10         {
    11             if (root == nullptr)
    12                 break;            
    13             for (slow = root, fast = root, step = k;;)
    14             {
    15                 fast = move(fast, step);
    16                 if (fast != nullptr)
    17                     slow = slow->next;
    18                 else 
    19                     break;
    20             }
    21             res[i] = root;
    22             if (slow->next != nullptr)
    23             {
    24                 root = slow->next; 
    25                 slow->next = nullptr;
    26             }
    27             else
    28                 break;
    29             step--;
    30         }
    31         return res;
    32     }
    33     ListNode* move(ListNode *node, int step)
    34     {
    35         for(;step > 0;)
    36         {
    37             node = node->next;
    38             step--;
    39             if (node == nullptr)
    40                 break;
    41         }
    42         return node;
    43     }
    44 };
  • 相关阅读:
    令人惊艳的算法——蒙特卡洛采样法
    肺炎确诊人数增长趋势拟合和预测(截止1月28日)
    「07」回归的诱惑:深入浅出逻辑回归
    实现一个简易版Webpack
    nrm——快速切换npm源
    7个有用的JavaScript技巧
    JSON Web Token 是什么?
    【译】强化表单的9个Vue输入库
    【译】如何使用Vue过渡效果来提升用户体验
    【译】JavaScript Source Maps浅析
  • 原文地址:https://www.cnblogs.com/cuancuancuanhao/p/8411132.html
Copyright © 2011-2022 走看看