题意分析

  • 给你一个长度为n的序列,需要我们将这个序列分为连续的k部分,要求分的所有的情况里面,对于每个部分的数字的和,要求所有的部分数字的和的最小的最大化。
  • 样例解释
    有3种分法
    [1],[2,1,5],数字和分别为1,8,最小值为1
    [1,2][1,5],数字和分别为3,6,最小值为3
    [1,2,1],[5]数字和分别为4,5,最小值为4
    则最小值的最大值为4。

思路分析

  • 我们知道,对于这种类型的题目,要我们求最小值最大化或者最大值最小化的情况,我们一般是可以使用二分的方法进行求解的。我们先利用二分枚举最后的结果。然后对于我们枚举的每个值,我们通过一个函数进行判断。那么这个函数如何判断呢?
  • 我们发现,对于最后的结果,我们按照顺序进行划分,如果当前的值超过了我们枚举的mid,那么我们就可以将这些数字划分为同一部分,然后,我们判断最后的划分情况大于等于mid的有多少个,与k进行比较。如果比k大,那么说明我们的枚举的最小值还可以更大。否则,就更小。更新左右区间即可。

图片说明

  • judge函数如下
    // 我们假设最小值为mid
    bool judge(int k,int mid,vector<int>&a){
        int num=0;
        int sum=0;
        for(auto x:a){
            sum+=x;
            if(sum>=mid){
                num++;
                sum=0;
            }
        }
        return num>=k;
    }

写法一 C++版

  • 代码如下
    • 假设a数组的和为s,二分的时间复杂度为,judge函数的判断的时间复杂度为.所以总的时间复杂度为
    • 只开了少数几个变量进行求解,空间复杂度为
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param n int整型 
     * @param k int整型 
     * @param a int整型vector 
     * @return int整型
     */
    // 我们假设最小值为mid,那么小于最小值的就必须要添一个知道满足大于等于这个mid
    bool judge(int k,int mid,vector<int>&a){
        int num=0;
        int sum=0;
        for(auto x:a){
            sum+=x;
            // 如果这一部分的所有的数字的和大于等于mid,那么就把这些划分为一块
            if(sum>=mid){
                num++;
                sum=0;
            }
        }
        // 最后的块数和k进行比较
        return num>=k;
    }
    int solve(int n, int k, vector<int>& a) {
        // write code here
        int l=0,r=0,mid;
        for(auto x:a){
            r+=x;
        }
        int ans=0;
        while(l<=r){
            mid=(l+r)>>1;
           // std::cout<<"mid:"<<mid<<endl;
            // 如果最后的结果大于等于mid,左边界右移
            if(judge(k,mid,a)){
                l=mid+1;
                ans=max(ans,mid);
            }else{
                // 如果最后的结果小于mid,右边界左移
                r=mid-1;
            }
        }
        return ans;
    }
};

写法二 Go语言版

  • 看写Go的不多,那么我来贡献一波go的代码。时间和空间都是100%,QAQ。

  • 代码如下

    • 假设a数组的和为,二分的时间复杂度为,judge函数的判断的时间复杂度为.所以总的时间复杂度为
    • 只开了少数几个变量进行求解,空间复杂度为
package main


/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * 
 * @param n int整型 
 * @param k int整型 
 * @param a int整型一维数组 
 * @return int整型
*/
func solve( n int ,  k int ,  a []int ) int {
    // write code here
    l := 0
    r := 0
    // 先进行遍历得到所有的数字的和作为右边界
    for _, value := range a {
        r+=value
    }
    var mid int
    ans := 0
    for l<=r {
        // 二分区间中点
        mid = (l+r)/2
        num := 0
        sum := 0
        for _, value := range a {
            sum+=value
            if(sum>=mid){
                num++
                sum=0
            }
        }
        // 如果可以分的块数超过k,那么左边界右边移动
        if(num>=k){
            // 维护答案的最大值
            if(ans<mid) {
                ans=mid
            }
            l=mid+1
        }else{
            // 否则右边界左边移动
            r=mid-1
        }
    }

    return ans
}