題目描述:將陣列 nums 分割成恰好 k 個非空連續子陣列,使得各子陣列總和的最大值最小化,求該最小化的最大值。
解題思路:答案具有單調性:若某個上限值 mid 可以使陣列被分成不超過 k 個子陣列(每個子陣列的和 ≤ mid),則任何 > mid 的值也同樣可行。因此對答案範圍 [max(nums), sum(nums)] 做二分搜尋。驗證函數採貪心策略:從左到右累加元素,一旦加入下一個元素會超過 mid 就開啟新的子陣列;最後統計需要幾段,若段數 ≤ k 則 mid 可行。下界設為 max(nums) 是因為任一元素必然屬於某個子陣列,其值就是那個子陣列和的最小可能下限。
時間複雜度:O(n log(sum(nums))) — 二分搜尋範圍最大為 sum(nums) - max(nums),約 O(log(sum(nums))) 輪;每輪的驗證函數線性掃描陣列,耗時 O(n)。
空間複雜度:O(1) — 驗證函數只使用常數個計數器變數,不需要額外的陣列或遞迴堆疊空間。
1. Set lo = max(nums), hi = sum(nums)
2. While lo < hi:
a. mid = lo + (hi - lo) / 2
b. Greedily count parts: scan nums left-to-right, start new part when adding next element exceeds mid
c. If parts <= k: hi = mid (feasible, try smaller)
d. Else: lo = mid + 1 (not feasible, increase allowed sum)
3. Return lo
feasibility check:
parts = 1, current = 0
for each num:
if current + num > mid: parts++, current = num
else: current += num
return parts <= k方法一:動態規劃 — O(n^2 * k)
定義 dp[i][j] 為將前 i 個元素分成 j 段的最小化最大子陣列和。轉移為 dp[i][j] = min over all split points p of max(dp[p][j-1], sum(p+1..i))。搭配前綴和可在 O(1) 計算子陣列和,整體 O(n^2 * k)。當 n、k 較大時(如 n=1000, k=50)會超時,但能作為理解最優子結構的經典方式。
方法二:二分搜尋(本解法) — O(n log S) 對答案值域二分,配合貪心驗證,是本題最優解法。程式碼簡潔,且相較 DP 有更低的時間常數與空間需求,為面試首選解法。