410. 分割数组的最大值

博客围绕将非负整数数组分成 m 个非空连续子数组展开,目标是使这 m 个子数组各自和的最大值最小。介绍了普通代码和二分法两种实现方式,着重阐述二分法原理,通过不断缩小容量区间找到最优解,如示例中最终找到结果为 18。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给定一个非负整数数组和一个整数 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,在所有情况中最小。

我的代码 56ms

class Solution {
public:
    int splitArray(vector<int>& nums, int m) {
        
        vector<vector<long long>> f(nums.size()+1,vector<long long>(m+1,INT_MAX));
        f[0][1]=0;
        for(int i=1;i<f.size();i++)
            for(int j=1;j<=i&&j<=m;j++)
            {
                if(j==1) f[i][j]=f[i-1][1]+nums[i-1];
                long long last=0;
                for(int k=1;k<=i-j+1;k++)
                {
                    last+=nums[i-k];
                    f[i][j]=min(f[i][j],max(f[i-k][j-1],last));
                    if(last>=f[i][j]) break;
                }
            }
        return f[nums.size()][m];
    }
};

二分法 4ms

/用二分法去猜子数组的容量
//如7 2 5 10 8 假设只有一个子数组那么数组的容量为32 如果有5个子数组那容量就是最大的那个数 10
//所以从[10,32]之间用二分法
//第一次 mid = (10+32)/2=21 我们刚开始假设只有一个子数组,那么need=1, 然后把数字一个一个塞进去
//先塞7 7<21 继续 2 7+2<21 继续 7+2+5<21 继续 7+2+5+10>21 就意味着一个数组放不下我们让need+1=2
//然后把后面的塞完,我们把need和m对比一下
//如果比m大说明我们开的子数组太多,也就意味值我们数组容量太小 子数组数量*容量=数组和(不是很精确,大
//概是这个意思) 所以我们就从[22,32]区间中找
//否则在[10,21]中找
//我们这个例子从[10,21] 最后找到了18

class Solution {
public:
    bool can_split(vector<int>&nums,int m,long int medium)
    {
        int ans=1;
        long int sum=0;
        for(int i=0;i<nums.size();i++)
        {
            sum+=nums[i];
            if(sum>medium)
            {
                ans++;
                sum=nums[i];
            }
        }
        return (ans>m);  
    }          
    int splitArray(vector<int>& nums, int m) {
        int n=nums.size();
        long int left=0;
        long int right=0;
        for(int i=0;i<n;i++)
        {
            right+=nums[i];
            left=nums[i]>left?nums[i]:left;
        }
        while(left<right)
        {
            long int medium=(left+right)/2;
            if(can_split(nums,m,medium))
                left=medium+1;
            else
                right=medium;
        }
        return left;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值