1. 程式人生 > 實用技巧 >分隔連結串列(力扣第725題)

分隔連結串列(力扣第725題)

題目:

  給定一個頭結點為 root 的連結串列, 編寫一個函式以將連結串列分隔為 k 個連續的部分。每部分的長度應該儘可能的相等: 任意兩部分的長度差距不能超過 1,也就是說可能有些部分為 null。這k個部分應該按照在連結串列中出現的順序進行輸出,並且排在前面的部分的長度應該大於或等於後面的長度。返回一個符合上述規則的連結串列的列表。

  舉例: 1->2->3->4, k = 5 // 5 結果 [ [1], [2], [3], [4], null ]

示例:

輸入: 
root = [1, 2, 3], k = 5
輸出: [[1],[2],[3],[],[]]
解釋:
輸入輸出各部分都應該是連結串列,而不是陣列。
例如, 輸入的結點 root 的 val
= 1, root.next.val = 2, \root.next.next.val = 3, 且 root.next.next.next = null。 第一個輸出 output[0] 是 output[0].val = 1, output[0].next = null。 最後一個元素 output[4] 為 null, 它代表了最後一個部分為空連結串列。

分析:

  這個題最核心的部分就是根據k值與給定連結串列之間長度的比較結果,這裡以length作為給定連結串列的長度選擇對應的處理方式:

  k >= length時,結果陣列的前length填寫連結串列中的元素,每個陣列元素都是單個的連結串列的結點,陣列中剩下的值都為null

  k < length時,需要對連結串列的元素進行分組,此時結果陣列的大小是固定的,即為k,那麼我們需要將length個連結串列元素分成k組,而且要求任意兩個部分長度差至多為1,並且是這k個部分是連續的,那可以這麼做,首先先給每個部分分配相同數量指標,然後還會有剩餘的數量指標,剩餘的數量一定是小於k的,因為 length%k < k,那麼根據任意兩個部分長度差不能超過1的原則,就將這未分配的剩餘數量指標,從左到右依次分配給每個部分,一個部分多出一個元素。每個部分的數量如下:

  length/k + 1,length/k + 1,length/k + 1,……,length/k (加1的是前length%k個部分)

程式碼實現:

public ListNode[] splitListToParts(ListNode root, int k) {
        ListNode[] res = new ListNode[k];
        if (root == null){
            
            for (int i = 0; i < k; i++) {
                res[i] = null;
            }
            return res;
        }
        ListNode p = root;
    
        int length = 0;
        while (p != null){
            
            length++;
            p = p.next;
        }
        p = root;
        if (k >= length){

            for (int i = 0; i < length; i++) {
                
                res[i] = new ListNode(p.val);
                p = p.next;
            }
        }else {
            int[] part_nums = new int[k];
            Arrays.fill(part_nums,length/k);

            for (int i = 0; i < (length % k); i++) {
                part_nums[i] = part_nums[i] + 1;
            }
            p = root;
            for (int i = 0; i < part_nums.length; i++) {

                ListNode node = new ListNode(-1);
                ListNode q = node;
                for (int j = 0; j < part_nums[i]; j++) {
                    
                    ListNode node1 = new ListNode(p.val);
                    node1.next = q.next;
                    q.next = node1;
                    q = q.next;
                    p = p.next;
                }
                res[i] = node.next;
            }
        }
        return res;
    }

我的程式碼有點垃圾,所以參考了cyc2018,我倆的思路是一樣的,但是他在實現上彰顯了大神的功力,即直接將原有的連結串列分隔成結果陣列中的每個部分,學習一下:

public ListNode[] splitListToParts(ListNode root, int k) {
     int N = 0;
    ListNode cur = root;
    while (cur != null) {
        N++;
        cur = cur.next;
    }
    int mod = N % k;
    int size = N / k;
    ListNode[] ret = new ListNode[k];
    cur = root;
    for (int i = 0; cur != null && i < k; i++) {
        ret[i] = cur;
        int curSize = size + (mod-- > 0 ? 1 : 0);
        for (int j = 0; j < curSize - 1; j++) {
            cur = cur.next;
        }
        ListNode next = cur.next;
        cur.next = null;
        cur = next;
    }
    return ret;
    }

參考:

https://github.com/CyC2018/CS-Notes/blob/master/notes/Leetcode%20%E9%A2%98%E8%A7%A3%20-%20%E9%93%BE%E8%A1%A8.md#9-%E5%88%86%E9%9A%94%E9%93%BE%E8%A1%A8