• Leetcode 410. 分割数组的最大值(困难) 二分查找高阶应用


    labuladong讲解

    410. 分割数组的最大值(困难)

    题目:

     题目讲解:

    给你输入一个数组 nums 和数字 m,你要把 nums 分割成 m 个子数组。

    肯定有不止一种分割方法,每种分割方法都会把 nums 分成 m 个子数组,这 m 个子数组中肯定有一个和最大的子数组对吧。

    我们想要找一个分割方法,该方法分割出的最大子数组和是所有方法中最大子数组和最小的。

    请你的算法返回这个分割方法对应的最大子数组和。

    思路:

    现在题目是固定了 m 的值,让我们确定一个最大子数组和;所谓反向思考就是说,我们可以反过来,限制一个最大子数组和 max,来反推最大子数组和为 max 时,至少可以将 nums 分割成几个子数组。

    比如说我们可以写这样一个 split 函数:

    // 在每个子数组和不超过 max 的条件下,
    // 计算 nums 至少可以分割成几个子数组
    int split(int[] nums, int max);

    比如说 nums = [7,2,5,10],若限制 max = 10,则 split 函数返回 3,即 nums 数组最少能分割成三个子数组,分别是 [7,2],[5],[10]

    那如果我们找到一个最小 max 值,满足 split(nums, max) 和 m 相等,那么这个 max 值不就是符合题意的「最小的最大子数组和」吗?

    现在就简单了,我们只要对 max 进行穷举就行,那么最大子数组和 max 的取值范围是什么呢?

    显然,子数组至少包含一个元素,至多包含整个数组,所以「最大」子数组和的取值范围就是闭区间 [max(nums), sum(nums)],也就是最大元素值到整个数组和之间。

    class Solution {
    public:
        int splitArray(vector<int>& nums, int m) {
            //取值范围[max(nums), sum(nums)]
            int lo=0,hi=0;
            for(int i=0;i<nums.size();++i){
                lo=max(lo,nums[i]);
                hi+=nums[i];
            }
            while(lo<=hi){
                int mid=lo+(hi-lo)/2;
                int count=split(nums,mid);
                if(count<m){
                    //需要增大count,则需减小max,缩小右边界
                    hi=mid-1;
                } else if(count>m){
                    //减小count,需要增大max,缩小左边界
                    lo=mid+1;
                } else{
                    //求解左侧边界问题,所以相等时缩小右边界
                    hi=mid-1;
                }
            }
            return lo;
        }
        // 在每个子数组和不超过 max 的条件下,
        // 计算 nums 至少可以分割成几个子数组
        int split(vector<int>& nums, int max){
            //最小为1堆
            int count=1;
            int sum=0;
            for(int i=0;i<nums.size();++i){
                //当总和大于max,新开一堆
                if(sum+nums[i]>max){
                    count++;
                    sum=nums[i];
                }else{
                    sum+=nums[i];
                }
            }
            
            return count;
        }
    };
  • 相关阅读:
    拉格朗日乘子法
    EM算法
    最大似然估计
    理解先验概率 后验概率 似然函数
    似然函数理解
    markdown 语法规则
    bash101总结
    hmm和Veterbi算法(一)
    Kaldi 安装
    通俗的解释交叉熵与相对熵
  • 原文地址:https://www.cnblogs.com/zl1991/p/15944886.html
Copyright © 2020-2023  润新知