↓快轉到主要內容
  1. LeetCode/

LeetCode 1354: Construct Target Array With Multiple Sums

·1 分鐘· ·
LeetCode Hard Heap Math Greedy
Wei Yi Chung
作者
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
目錄

基本資料
#

難易度: hard 第一次嘗試:2026-09-07

  • 提交紀錄:Time Limit Exceeded → Accepted

解題思路
#

正著做選擇太多,反著做:

每次操作會把某個位置設成「當時的總和」,而總和一定比其他任何元素都大,所以目前陣列的最大值,一定是最後一次被設定的那個位置。

反推一步:設最大值是 mx、其他元素的和是 rest,上一步這個位置的值是 mx - rest。

用 max-heap 反覆取出最大值、還原上一步,直到全部變成 1 就成功;如果還原出來的值小於 1,就失敗。

我的第一版:一次只還原一步
#

preNum = preSum - (currSum - preSum)

例如 [1, 1000000000]:每次只減 1,要跑 10^9 次,TLE。

改進:用取餘數一次跳完
#

如果 mx 比 rest 大很多,同一個位置會被連續還原很多次,每次減 rest,直到小於 rest 為止,這就是 mx % rest。

需要注意的邊界:

  • rest == 1:例如 [1, x],一直減 1 一定能減到 1,直接回傳 True。要先處理,因為 x % 1 == 0 會被誤判。
  • rest == 0(只有一個元素,而且不是 1),或 mx <= rest:沒辦法再往回推,回傳 False。
  • mx % rest == 0:還原出來是 0,不合法,回傳 False。

正確解法
#

import heapq

class Solution:
    def isPossible(self, target: List[int]) -> bool:
        total = sum(target)
        heap = [-x for x in target]
        heapq.heapify(heap)

        while True:
            mx = -heapq.heappop(heap)
            if mx == 1:
                return True                    # 最大值是 1,全部都是 1
            rest = total - mx
            if rest == 1:
                return True
            if rest == 0 or mx <= rest:
                return False
            prev = mx % rest
            if prev == 0:
                return False
            total = rest + prev
            heapq.heappush(heap, -prev)

複雜度
#

時間 O(n + log(S) · log n),S 是總和:最大值至少佔總和的一半,而取餘數後它會變成不到原本的一半,所以每輪總和至少縮小到 3/4,迴圈只會跑 O(log S) 次。空間 O(n)。

要特別避免的錯誤
#

  • 一次只還原一步:差距大時 TLE。
  • 沒有先處理 rest == 1:x % 1 == 0 會被當成失敗。
  • 單一元素的陣列:rest == 0,只有 [1] 是 True。

面試口說整理
#

我反著做:每次設定的值都是當時的總和,所以目前的最大值一定是最後被設定的,上一步的值是最大值減掉其他元素的和。用 max-heap 反覆取最大值還原;差距很大時同一個位置會被連續還原,所以用取餘數一次跳完。其他元素和是 1 時一定可以,是 0 或不小於最大值時不行,取餘數得到 0 也不行。全部變成 1 就成功。

相關文章

LeetCode 499: The Maze III
·2 分鐘
LeetCode Hard Graph Dijkstra Shortest-Path Heap Matrix
LeetCode 499 解題筆記:Dijkstra 的優先度用 (距離, 路徑字串),滾動途中經過洞就要停下
LeetCode 1627: Graph Connectivity With Threshold
·1 分鐘
LeetCode Hard Math Number-Theory Union-Find Array
LeetCode 1627 解題筆記:不用兩兩算 GCD;對每個 z > threshold,把 z 的所有倍數連起來,總共 O(n log n) 次合併
LeetCode 2193: Minimum Number of Moves to Make Palindrome
·1 分鐘
LeetCode Hard Two-Pointers Greedy String Binary-Indexed-Tree
LeetCode 2193 解題筆記:貪心處理最外層:拿最後一個字元,把它最左邊的同伴換到最前面,花費是那個位置;落單的字元最後在正中間,花費是它到中間的距離
LeetCode 420: Strong Password Checker
·2 分鐘
LeetCode Hard Greedy String
LeetCode 420 解題筆記:分長度三種情況,太長時優先刪除 len % 3 == 0 的重複段來抵銷取代次數
LeetCode 2912: Number of Ways to Reach Destination in the Grid
·2 分鐘
LeetCode Hard Dynamic-Programming State-Machine Math Combinatorics
LeetCode 2912 解題筆記:格子太多,但相對終點只分四類:終點、同一列、同一行、都不同;每一類的總方法數一起轉移,O(k)
LeetCode 60: Permutation Sequence
·1 分鐘
LeetCode Hard Math Combinatorics Recursion
LeetCode 60 解題筆記:k 改成 0-indexed,第一位決定之後剩下 (n-1)! 種排法;k // (n-1)! 就是第一位在剩下的數字裡排第幾,取出後繼續處理下一位