LeetCode: Split Array Largest Sum

题目:
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:
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.

题目给出一个数组nums和分割数m,将nums分割成m份,可以用不同的分割方法,要求找出m份数组中最大和的最小值result。

参考了网上二分法的算法:假设数组nums的长度为n,整个数组最多分成n份,此时这n份数组中的最大和即为nums数组中最大的元素,且是最小的最大和(因为只有一种分法),result=max(nums[i]);整个数组最少只分成一份,此时最小的最大和为所有元素之和(只有一种分法),result=sum(nums[i])。所以我们要求的result值应该是介于max(nums[i])和sum(nums[i])之间的,使用二分法来求result:求出当前范围内的中间元素mid,判断result值是否可能等于mid,如果可能,缩小范围,high=mid,求出更小的可行解;如果不可能,说明result是一个更大的数,low=mid+1。直到low=high。

判断result值是否可能等于mid:从前往后遍历数组,将前i个元素相加得到sum,如果sum+nums[i+1]不大于mid,将nums[i+1]加到sum中。否则,说明前i个元素必须被分成一份才能使result值不超过mid,份数加一,从i+1个元素开始继续遍历,判断遍历完后的份数是否超过m,如果超过,则说明result值不能等于mid,否则说明result值可能等于mid。

判断result值是否可能等于mid的时间复杂度为o(n),二分法的时间复杂度为o(logn),所以算法的时间复杂度为o(nlogn)。要注意Note中的提示,low,high,mid,result的值可能非常大,为了表示它们,要使用长整型变量。

Accepted的代码:

class Solution {
public:
    int splitArray(vector<int>& nums, int m) {
        //得到最大值和最小值
        long int low=nums[0],high=0;
        for(int i=0;i<nums.size();i++)
        {
            if(nums[i]>low) low=nums[i];
            high+=nums[i];
        }
        //二分搜索
        while(low<high)
        {
            long int mid=(low+high)/2;
            if(isTrue(nums,mid,m)) high=mid;
            else low=mid+1;
        }
        return low;
    }
    //判断结果是否可能为mid
    bool isTrue(vector<int>& nums,int mid,int m)
    {
        int count=1;//数组的分段数
        int sum=0;//每小段的和
        for(int i=0;i<nums.size();i++)
        {
            if(sum+nums[i]<=mid)
            {
                sum+=nums[i];
            }
            else 
            {
                count++;
                sum=nums[i];
                if(count>m) return false;
            }
        }
        return true;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值