410. 分割数组的最大值

299 篇文章 1 订阅
227 篇文章 1 订阅

给定一个非负整数数组 nums 和一个整数 m ,你需要将这个数组分成 m 个非空的连续子数组。

设计一个算法使得这 m 个子数组各自和的最大值最小。

示例 1:

输入:nums = [7,2,5,10,8], m = 2
输出:18
解释:
一共有四种方法将 nums 分割为 2 个子数组。
其中最好的方式是将其分为 [7,2,5] 和 [10,8] 。
因为此时这两个子数组各自的和的最大值为18,在所有情况中最小。
示例 2:

输入:nums = [1,2,3,4,5], m = 2
输出:9
示例 3:

输入:nums = [1,4,4], m = 3
输出:4

提示:

1 <= nums.length <= 1000
0 <= nums[i] <= 106
1 <= m <= min(50, nums.length)

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/split-array-largest-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

正式开始之前,先要感慨一下,写博客真的太有必要了,尤其是 二刷甚至 三刷算法的时候,能直接把你的思路拉回当当初写博客的那个思路,真的舒服,比如这个题,我第一次做是在 21 年的 11 月份,当时做完也是日常写博客写解析,今天再做的时候,发现根本读不懂,仿佛这个题是个新题,全 nm 忘了,所以我就去翻以前的博客,思路瞬间清晰,直接想起来了,三下五除二就搞定了,而且算法复盘真的很有必要,不多 bb 了,直接上解析:

本题,你可能刚开始读不懂题目,不过没关系,一点点分析,题目中说,要求 m 各子数组的最大值的最小值,比如 [7,2,5,10,8] 分为两部分,最大值的最小,那就是 725, 10 8,最大值是 18,如果是 72, 5 10 8,那么最大值就是 23 了,所以,可以推断出,答案在 数组的最大值 Math.max 和 数组总和之间,此时完全可以使用二分查找来解决,每次的 mid 值设置为 target,使用 checkOut 函数判断

checkOut 函数,就是本题的核心,其实就是一个分组的问题,以 target 为标准,当某个组,超过 target 了,就加一个新组,一看代码就懂了,最后统计的 count 就是分组的个数
如果分组的个数等于 m,但是不能保证是最优解(也即是最大值的最小值)继续缩短右边界,让 target 变小 求解。
如果分组的个数小于 m,说明分的组太少了,也就是 target 太大了,导致分组不够,此时缩短右边界,让 target 变小。
如果分组的个数大于 m,说明分的组太多了,也就是 target 的值小了,导致分的组多,此时缩短左边界,让 target 变大。

class Solution {
    public int splitArray(int[] nums, int m) {
        int left = 0, right = 0;
        for (int num : nums) {
            left = Math.max(left, num);
            right += num;
        }
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (checkOut(nums, mid, m)) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        return left;
    }
    public boolean checkOut(int[] nums, int target, int m) {
        int count = 1, sum = 0;
        for (int num : nums) {
            if (sum + num > target) {
                count++;
                sum = num;
            } else {
                sum += num;
            }
        }
        return count <= m;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_努力努力再努力_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值