1. 程式人生 > >410. Split Array Largest Sum

410. Split Array Largest Sum

into false 變化 java public ons urn for follow

Given an array which consists of non-negative integers and an integer m, 
you can split the array into m non-empty continuous subarrays.
Write an algorithm to minimize the largest sum among these m subarrays. Note: Given m satisfies the following constraint:
1 ≤ m ≤ length(nums) ≤ 14,000. Examples: Input: nums
= [7,2,5,10,8] m = 2 Output: Explanation: There are four ways to split nums into two subarrays. The best way is to split it into [7,2,5] and [10,8], where the largest sum among the two subarrays is only 18.

二分法:

public int splitArray(int[] nums, int m) {
        long sum = 0;
        int max = 0;
        for(int num: nums){
            max = Math.max(max, num);
            sum += num;
        }
        return (int)binarySearch(nums, m, sum, max);
    }
    //二分查找
    private long binarySearch(int[] nums, int m, long high, long low){
        long mid = 0;
        while(low < high){
            mid = (high + low)/2;
            //驗證是否滿足,也就是這麽大的值有可能出現麽
            if(valid(nums, m, mid)){
                high = mid;
            }else{
                low = mid + 1;
            }
        }
        return high;
    }

    /**
     * 驗證這個值是否合法
     * */
    private boolean valid(int[] nums, int m, long max){
        int cur = 0;
        int count = 1;
        //是否有多余m個片段or區間,大於給定值的max的,如果有了,那麽就不合法了,因為這樣劃分就不止m個,及max太小
        for(int num: nums){
            cur += num;
            if(cur > max){
                cur = num;
                count++;
                if(count > m){
                    return false;
                }
            }
        }
        return true;
}

動歸: 最大, 最小, 不能排序, 而且是求區間和的改寫, 先考慮用一維動歸, dp[m]表示分為m組, 寫不出狀態轉移方程. 並且, 這是最大值最小的問題, 先找最大, 再找最小, 所以用二維數組, 題中就是組數, 和第幾個人是變量, 因此dp[m][n] 表示將n個人分為m組的結果值, 這樣有了兩層外循環, 看遞推公式與兩層外循環的關系:

dp[m][n] = min (dp[m][n], Un-1 j = m - 1 max(dp[m - 1][j], sum[n] - sum[j]) (內循環多是最後一次分割點位置變化, 和前一次分割的關系 )

因為dp[m - 1][j] 不能直接得到, 所以需要 外循環 動歸到dp[m][n], 其實想想也很簡單, 只有外循環先建立起來了, 才有內循環的遞推公式.

一維狀態方程常考慮: 要不要該點,

二維狀態方程常考慮: 分割點(與題目的值(sums[j] - sums[k]) 聯系最緊密 , 當前分割的次數與前一次數有什麽關系

subarray 和的問題常轉化為 區間和的問題, (sums[j] - sums[k])

起點的初始化要正常, 中間點的初始化時為了比較(min, max) 等.------知道的初始化正常值, 不知道的初始化為對立值.

public int splitArray(int[] nums, int m) {
        int n = nums.length;
        int[][] dp = new int[m + 1][nums.length + 1];
     
        int[] sums = new int[n + 1];
        for (int i = 1; i <= n; ++i) {
            sums[i] = sums[i - 1] + nums[i - 1];
            
        }
        for (int i = 0; i <= m; ++i) {
            for (int j = 0; j <= n; ++j) {
                dp[i][j] = Integer.MAX_VALUE;
            }
        }
        dp[0][0] = 0;
        for (int i = 1; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                for (int k = i - 1; k < j; ++k) {
                    int val = Math.max(dp[i - 1][k], sums[j] - sums[k]);
                    dp[i][j] = Math.min(dp[i][j], val);
                }
            }
        }
        return dp[m][n];
}

  

410. Split Array Largest Sum