[LeetCode] #725. Split Linked List in Parts

題目

Given a (singly) linked list with head node root, write a function to split the linked list into k consecutive linked list "parts".

The length of each part should be as equal as possible: no two parts should have a size differing by more than 1. This may lead to some parts being null.

The parts should be in order of occurrence in the input list, and parts occurring earlier should always have a size greater than or equal parts occurring later.

Return a List of ListNode's representing the linked list parts that are formed.

Examples 1->2->3->4, k = 5 // 5 equal parts [ [1], [2], [3], [4], null ]

直覺解

構想:

先計算整個 list 有多長,分成「list 長度 < k」和「list 長度 >= k」兩種狀況處理。
若 list 長度 < k,則每個 part 只有一個節點,剩下的位置就用 null 補滿。
若 list 長度 >= k,則計算每個 part 有多長,最後根據每個 part 的長度去分割 list。

javascript 實作:

const splitListToParts = function(root, k) { 
    const result = []
    let current = root
    let prevNode
    let length = 0
    // 計算整個 list 有多長
    while (current !== null) {
        current = current.next
        length++
    }

    // 處理 list 長度 < k 的狀況
    if (length < k) {
        for (let i = 0; i < length; i++) {
            result.push(root)
            prevNode = root
            root = root.next
            prevNode.next = null
        }

        for (let i = 0; i < k - length; i++) {
            result.push(null)
        }
        return result
    }

    // 處理 list 長度 >= k 的狀況
    // 1. 計算每個 part 有多長
    const quotient = Math.floor(length / k)
    let remainder = length % k
    const lengthOfParts = []
    for (let i = 0; i < k; i++) {
        if (remainder > 0) {
            lengthOfParts.push(quotient + 1)
            remainder--
        } else {
            lengthOfParts.push(quotient)
        }
    }

    // 2. 根據每個 part 的長度去分割 list
    lengthOfParts.forEach((length, index) => {
        result.push(root)
        for (let i = 0; i < length; i++) {
            if (root === null) {
                break
            }
            prevNode = root
            root = root.next
        }

        if (prevNode) {
            prevNode.next = null
        }
    })
    return result
}

效能:

Runtime: 96 ms, faster than 19.44% of JavaScript online submissions for Split Linked List in Parts.
Memory Usage: 41 MB, less than 18.06% of JavaScript online submissions for Split Linked List in Parts.

構想:

先計算整個 list 有多長,再計算每個 part 有多長,最後根據每個 part 的長度去分割 list。

python 3 實作:

def splitListToParts(self, root: ListNode, k: int) -> List[ListNode]: 
    result = []

    # count length of linked list
    length = 0
    current = root
    while current:
        current = current.next
        length += 1

    # count length of each parts
    part_length = []
    for i in range(k):
        part_length.append(length // k)
    for i in range(length % k):
        part_length[i] += 1

    # split linked lis
    for i in range(k):
        if root:
            result.append(root)
            for i in range(part_length[i]):
                current = root
                root = root.next
            current.next = None
        else:
            result.append(None)

    return result

效能:

Runtime: 40 ms, faster than 56.69% of Python3 online submissions for Split Linked List in Parts.
Memory Usage: 14.8 MB, less than 69.70% of Python3 online submissions for Split Linked List in Parts.

參考別人的解

python 3 實作優化一:

構想:計算每個 part 的長度時,不再使用 for 回圈一個一個算,改成直接計算「比較長的有幾個」、「比較短的有幾個」。

def splitListToParts(self, root: ListNode, k: int) -> List[ListNode]: 
    result = []

    # count length of linked list
    length = 0
    current = root
    while current:
        current = current.next
        length += 1

    # count length of each parts
    chunk_size = length // k
    larger_chunk = length % k
    part_length = [chunk_size + 1] * larger_chunk + [chunk_size] * (k - larger_chunk)

    # split linked lis
    for i in range(k):
        if root:
            result.append(root)
            for i in range(part_length[i]):
                current = root
                root = root.next
            current.next = None
        else:
            result.append(None)

    return result

效能:

Runtime: 28 ms, faster than 98.33% of Python3 online submissions for Split Linked List in Parts.
Memory Usage: 14.7 MB, less than 69.70% of Python3 online submissions for Split Linked List in Parts.


python 3 實作優化二:

構想:不再另外宣告 result = [] 來儲存答案,而是直接把 part_length 改造成答案。為了方便對照,刪掉的地方姑且用 # 註解掉。

def splitListToParts(self, root: ListNode, k: int) -> List[ListNode]: 
    # result = []

    # count length of linked list
    length = 0
    current = root
    while current:
        current = current.next
        length += 1

    # count length of each parts
    chunk_size = length // k
    larger_chunk = length % k
    part_length = [chunk_size + 1] * larger_chunk + [chunk_size] * (k - larger_chunk)

    # split linked list
    for index, length in enumerate(part_length):
        if root:
            part_length[index] = root
            for i in range(length):
                current = root
                root = root.next
            current.next = None
        else:
            part_length[index] = None

    return part_length

效能(好像沒有比較節省空間):

第一次

Runtime: 40 ms, faster than 56.69% of Python3 online submissions for Split Linked List in Parts.
Memory Usage: 14.7 MB, less than 69.70% of Python3 online submissions for Split Linked List in Parts.

第二次

Runtime: 32 ms, faster than 92.94% of Python3 online submissions for Split Linked List in Parts.
Memory Usage: 14.8 MB, less than 69.70% of Python3 online submissions for Split Linked List in Parts.

第三次

Runtime: 28 ms, faster than 98.33% of Python3 online submissions for Split Linked List in Parts.
Memory Usage: 14.8 MB, less than 69.70% of Python3 online submissions for Split Linked List in Parts.

Comments

Popular posts from this blog

Alpha Camp 全端開發課程學習心得

在 javascript 用 regular expression 為金額加上千位數分隔符號

shop_platform - sqlalchemy.exc.TimeoutError