[高级二分法]leetcode410:分割数组的最大值(hard)

题目:
[高级二分法]leetcode410:分割数组的最大值(hard)_第1张图片

题解:
说实话这题真的挺难的,不愧为hard级别的题目。解题思路我是参考评论区大佬的,说一下我所理解的思路

  • 1)首先题目要求我们将数组划分为m个子数组,并要求这m个子数组各自和的最大值在所有情况中最小,那么m个子数组各自和的最大值必定在max(nums)和sum(nums)这个区间范围内,所以我们就要利用二分法来划分此区间范围,begin=max(nums);end=sum(nums);mid=begin+(end-begin)/2;

  • 2)还有一个最关键的地方就是计算划分的数组个数count,数组前k项元素之和(k在代码中没有意义,只是为了将问题更好的说明)大于mid则count+1,表示划分一次数组。然后再重新计算k+1项开始的子数组的元素之和与mid的比较来划分子数组(也就是count是否+1)直至遍历完整个数组。

  • 3)子数组划分完成,那么就需要比较count与m了。若count的值大于m则表示数组划分次数过多,也就是mid的值太小了(因为mid的值太小了,导致有多个子数组的总和值大于mid),这时我们需要在右边寻找m个子数组各自和的最大值了begin=mid+1(也就是确保下一次mid的值能大点);若count<=m表示数组划分次数过少,也就是mid的值太大了(因为mid的值太大了,导致只有少数几个子数组的值大于mid),这时我们需要在左边寻找m个子数组各自和的最大值end=mid(也就是确保下一次mid能小点)。最后循环结束的条件就是end=begin,也就是找到m个子数组各自和的最大值了。

class Solution {
public:

    //时间复杂度O(logn),空间复杂度为O(1)
    int splitArray(vector<int>& nums, int m) 
    {
        //begin表示数组中元素的最大值,end表示数组中元素的总和,[begin,end]表示的区间为子数组的最大值
        long begin=nums[0],end=0;
        for(auto num:nums)
        {
            end+=num;
            begin=begin>num?begin:num;
        }
        
        while(begin<end)
        {
            long mid=begin+(end-begin)/2;
            long temp=0;
            int count=1;//计算划分的子数组个数,必须从初始化为1
            for(auto num:nums)
            {
                temp+=num;
                if(temp>mid){temp=num;++count;}//若数组(从头到num的)子序列之和temp大于mid,划分一次数组
            }
            if(count>m)begin=mid+1;//count>m说明数组划分过多,也就是mid的值太小了,导致数组前面的一部分元素和就达到mid的标准了
            else end=mid;//当count与m相等时,说明mid的值偏大导致数组划分次数较少,或者mid的值刚好为目标值
        }
        return begin;
    }
};

你可能感兴趣的:(leetcode刷题,#,二分法)