leetcode 410. 分割數組的最大值(二分法)

1. 題目描述

給定一個非負整數數組和一個整數 m,你須要將這個數組分紅 m 個非空的連續子數組。設計一個算法使得這 m 個子數組各自和的最大值最小。

注意:
數組長度 n 知足如下條件:

1 ≤ n ≤ 1000
1 ≤ m ≤ min(50, n)
示例:

輸入:
nums = [7,2,5,10,8]
m = 2

輸出:
18

解釋:
一共有四種方法將nums分割爲2個子數組。
其中最好的方式是將其分爲[7,2,5] 和 [10,8],
由於此時這兩個子數組各自的和的最大值爲18,在全部狀況中最小。

來源:力扣(LeetCode)
連接:https://leetcode-cn.com/problems/split-array-largest-sum
著做權歸領釦網絡全部。商業轉載請聯繫官方受權,非商業轉載請註明出處。

 

2. 思路

核心,二分查找各個子數組和的最大值的最小狀況
    1. 子數組的最大值是有範圍的,即在區間[max(nums),sum(nums)]之中。
    2. 令l=max(nums),h=sum(nums),mid=(l+h)/2,計算數組和最大值不大於mid對應的子數組個數cnt(這個是關鍵!)
    3. 若是cnt>m,說明劃分的子數組多了,即咱們找到的mid偏小,故l=mid+14. 若是cnt<=m,說明劃分的子數組少了,即mid偏大(或者正好就是目標值),故h=mid。

 

3. 代碼

class Solution {
    public int splitArray(int[] nums, int m) {
        /**子數組的最大值是有範圍的,即在區間[max(nums),sum(nums)]之中。*/
        long l = nums[0];
        long h = 0;
        for (int i : nums) {
            h += i;//max(nums)
            l = l > i ? l : i;//sum(nums)
        }
        /**計算數組和最大值不大於mid對應的子數組個數cnt*/
        while (l<h) {//二分法找分割數組的最大值
            long mid = (l + h) / 2;
            long temp = 0;
            int cnt = 1;//初始值爲1,
            for(int i:nums) {
                temp += i;
                if(temp>mid) {//若是超過mid,開啓新的一組
                    temp = i;//每一個子數組和
                    ++cnt;//子數組個數
                }
            }
            if(cnt>m)
                l = mid + 1;//若是cnt>m,說明劃分的子數組多了,即咱們找到的mid偏小,故l=mid+1;
            else
                h = mid;//若是cnt<=m,說明劃分的子數組少了,即mid偏大(或者正好就是目標值),故h=mid。
        }
        return (int)l;
    }
}
相關文章
相關標籤/搜索