410. Split Array Largest Sum

410. Split Array Largest Sum

題目連接: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])優化

相關文章
相關標籤/搜索