LeetCode 410-Split Array Largest Sum(二分,最优化(最大值最小))

LeetCode 410-Split Array Largest Sum

题干:

给定一个数组 n u m s nums nums和一个数 k k k,要求把 n u m s nums nums分割成 k k k个连续非空子数组。问最大子数组和能达到的最小值为多少(即,找到一个分割方法,使得用该方法分割出的最大子数组和是所有方法中最小的,输出这个最小值)。

Input: nums = [7,2,5,10,8], k = 2
Output: 18
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.

解:

同LeetCode1011货物装载,即:有一艘货船和若干货物,每个货物的重量是 n u m s [ i ] nums[i] nums[i],需要 k k k天将这些货物全部运走,问货船的最小载重量是多少。

设最大子数组和为 x x x。可以得到,最大子数组和越大,分割所需要的组数越小,最大子数组和越小,分割所需要的组数越多。所以最大子数组和和分割数组所需要的组数是一个单调不递增关系。

所以,可以定义 f ( x ) f(x) f(x)为:以最大子数组和为 x x x来分割数组,所需要的组数。

又由题,需要限制 f ( x ) = = m f(x)==m f(x)==m

所以该题所求的是:满足 f ( x ) = = m f(x)==m f(x)==m的条件下的最小 x x x。画图可得求的是左边界。

x x x的取值范围: l e f t = m a x ( n u m s [ i ] ) , r i g h t = ∑ n u m s [ i ] left=max(nums[i]), right=\sum nums[i] left=max(nums[i]),right=nums[i]

int f(vector<int>& nums,int x){
        int cnt = 1, res = x;
        for(int i: nums){
            if(res < i){
                ++cnt;
                res = x;
            }
            res -= i;
        }
        return cnt;
    }
int splitArray(vector<int>& nums, int k) {
        int left = 0, right = 0;
        for(int i: nums){
            left = max(left, i);
            right += i;
        }
        right += 1;
        int ans = left;

        while(left < right){
            int mid = left + ((right - left) >> 1);
            int cnt = f(nums, mid);
            if(cnt == k){
                ans = mid;
                right = mid;
            }
            else if(cnt < k) right = mid;
            else if(cnt > k) left = mid + 1;
        }
        return ans;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值