Split Linked List in Parts
Split a list into k roughly-equal parts (earlier parts at most one node larger).
4 min read
linked-list
Problem#
Split the list into k consecutive parts. Earlier parts may be at most one node larger than later parts. Return the array of k heads.
Examples#
[1,2,3], k = 5→[[1],[2],[3],[],[]][1,2,3,4,5,6,7,8,9,10], k = 3→[[1,2,3,4],[5,6,7],[8,9,10]]
Constraints#
0 <= length <= 100,1 <= k <= 50.
Approach#
Count length n. Each of the first n % k parts gets ⌈n / k⌉ nodes; the rest get ⌊n / k⌋. Walk and cut.
Solution#
class Solution {public: vector<ListNode*> splitListToParts(ListNode* head, int k) { int n = 0; for (ListNode* p = head; p; p = p->next) ++n; int base = n / k, extra = n % k; vector<ListNode*> ans(k, nullptr); ListNode* curr = head; for (int i = 0; i < k && curr; ++i) { ans[i] = curr; int size = base + (i < extra ? 1 : 0); for (int j = 0; j < size - 1; ++j) curr = curr->next; ListNode* nxt = curr->next; curr->next = nullptr; curr = nxt; } return ans; }};func splitListToParts(head *ListNode, k int) []*ListNode { n := 0 for p := head; p != nil; p = p.Next { n++ } base, extra := n/k, n%k ans := make([]*ListNode, k) curr := head for i := 0; i < k && curr != nil; i++ { ans[i] = curr size := base if i < extra { size++ } for j := 0; j < size-1; j++ { curr = curr.Next } nxt := curr.Next curr.Next = nil curr = nxt } return ans}from typing import List, Optional
class Solution: def splitListToParts(self, head: Optional[ListNode], k: int) -> List[Optional[ListNode]]: n = 0 p = head while p: n += 1 p = p.next base, extra = divmod(n, k) ans: List[Optional[ListNode]] = [None] * k curr = head for i in range(k): if not curr: break ans[i] = curr size = base + (1 if i < extra else 0) for _ in range(size - 1): curr = curr.next nxt = curr.next curr.next = None curr = nxt return ansfunction splitListToParts(head, k) { let n = 0; for (let p = head; p; p = p.next) n++; const base = Math.floor(n / k); const extra = n % k; const ans = new Array(k).fill(null); let curr = head; for (let i = 0; i < k && curr; i++) { ans[i] = curr; const size = base + (i < extra ? 1 : 0); for (let j = 0; j < size - 1; j++) curr = curr.next; const nxt = curr.next; curr.next = null; curr = nxt; } return ans;}class Solution { public ListNode[] splitListToParts(ListNode head, int k) { int n = 0; for (ListNode p = head; p != null; p = p.next) n++; int base = n / k, extra = n % k; ListNode[] ans = new ListNode[k]; ListNode curr = head; for (int i = 0; i < k && curr != null; i++) { ans[i] = curr; int size = base + (i < extra ? 1 : 0); for (int j = 0; j < size - 1; j++) curr = curr.next; ListNode nxt = curr.next; curr.next = null; curr = nxt; } return ans; }}function splitListToParts(head: ListNode | null, k: number): (ListNode | null)[] { let n = 0; for (let p = head; p; p = p.next) n++; const base = Math.floor(n / k); const extra = n % k; const ans: (ListNode | null)[] = new Array(k).fill(null); let curr: ListNode | null = head; for (let i = 0; i < k && curr; i++) { ans[i] = curr; const size = base + (i < extra ? 1 : 0); for (let j = 0; j < size - 1; j++) curr = curr!.next; const nxt: ListNode | null = curr!.next; curr!.next = null; curr = nxt; } return ans;}Editorial#
The n % k “extra” nodes are sprinkled into the first n % k parts, one each — that’s the “earlier parts may be one node larger” rule. The cut step (curr->next = nullptr) terminates each part; we capture the next-part head before nulling.
Complexity#
- Time: O(n + k).
- Space: O(k) (output).
Concept revision#
Related#