題目連接:https://leetcode.com/problems...java
枚舉全部可能的largest sum,找最小的那個,二分枚舉優化複雜度,由於數組不含負數,根據largest sum是否知足條件能夠二分結果。largest sum的範圍是(sum(nums)/m, sum(nums)),找當前largest sum是否存在,判斷存在的標準是:掃一遍array,看實現每一個subarray的sum都<=當前largest sum的時候subarray的數量是否小於等於mm
,注意求數組sum要用long,防止溢出。數組
public class Solution { public int splitArray(int[] nums, int m) { long sum = 0; for(int num : nums) sum += num; // binary search, find the minimum valid sum long l = sum / m; long r = sum; while(l < r) { long mid = l + (r - l) / 2; boolean valid = isValidSplit(nums, m, mid); if(valid) r = mid; else l = mid + 1; } return (int) l; } private boolean isValidSplit(int[] nums, int m, long sum) { int i = 0, n = nums.length; // count the minimum number of split int count = 0; // prev sum long prev = 0; // loop invariant: prev = 0, count = minimum splits so far while(i < n) { if(nums[i] > sum) return false; while(i < n && prev + nums[i] <= sum) { prev += nums[i++]; } count++; if(count > m) return false; prev = 0; } return count <= m; } }
還有一種dp的作法:
https://discuss.leetcode.com/...oop
dp的subproblem是:dp[i][j]: split nums[0:i] into j parts
,
dp的方程是:dp[i][j] = min{ max{dp[k][j-1], sum(nums[k+1:i+1])} }
,
每一個subproblem都遍歷一遍可能的k,選擇出最小的結果。注意因爲array不含負數,dp[k-1] <= dp[k]
而且sum(nums[k:i+1]) >= sum(nums[k+1:i+1])
,至關於一條遞增,一條遞減的線找交點,極端狀況沒有交點結果出如今兩端,因此依然能夠binary search找dp[k] == sum(nums[k+1:i+1])
。優化