leetcode2439. 最小化数组中的最大值 贪心or二分答案

  • https://leetcode.cn/problems/minimize-maximum-of-array

  • 给你一个下标从 0 开始的数组 nums ,它含有 n 个非负整数。

  • 每一步操作中,你需要:

  • 选择一个满足 1 <= i < n 的整数 i ,且 nums[i] > 0 。
    将 nums[i] 减 1 。
    将 nums[i - 1] 加 1 。
    你可以对数组执行 任意 次上述操作,请你返回可以得到的 nums 数组中 最大值 最小 为多少。

示例 1:

输入:nums = [3,7,1,6]
输出:5
解释:
一串最优操作是:
1. 选择 i = 1 ,nums 变为 [4,6,1,6]2. 选择 i = 3 ,nums 变为 [4,6,2,5]3. 选择 i = 1 ,nums 变为 [5,5,2,5] 。
nums 中最大值为 5 。无法得到比 5 更小的最大值。
所以我们返回 5 。
示例 2:

输入:nums = [10,1]
输出:10
解释:
最优解是不改动 nums ,10 是最大值,所以返回 10 。
 

提示:

n == nums.length
2 <= n <= 105
0 <= nums[i] <= 109

code

  • https://leetcode.cn/problems/minimize-maximum-of-array/solution/liang-chong-zuo-fa-er-fen-da-an-fen-lei-qhee6/

二分答案

  • 二分答案是一种常见的解题思路,通常用于求解满足某个条件的最大或最小值。其基本思路是首先确定答案的范围,然后在这个范围内进行二分查找,不断缩小答案的范围,直到找到符合条件的最优解。

  • 具体实现时,可以先定义一个判断函数,用于判断当前答案是否符合条件。然后根据题目要求,确定答案范围,比如可以将答案范围设为 [0, max],其中 max 是题目给定的最大值。接着进行二分查找,每次选择中间值 mid,调用判断函数判断 mid 是否符合条件,如果符合条件,则将答案范围缩小到 [mid+1, max],否则将范围缩小到 [0, mid-1],直到找到最优解为止。

  • 需要注意的是,二分答案适用于 问题的答案处在某个单调的区间内,即答案随着输入的增加或减少而单调递增或递减。比如: C h e c k ( x ) = T r u e , ∀ x ≥ t . 并且 C h e c k ( x ) = F a l s e , ∀ x ≤ t . Check(x)=True,\forall x\geq t. 并且 Check(x)=False,\forall x\leq t. Check(x)=True,xt.并且Check(x)=False,xt.

class Solution {
public:
    static bool check(vector &nums, int k) {//假设最小化数组中的最大值为k
		//下面对k进行验证
        long long have = 0;//前方的数字还可以帮我们后方的大数承载多少数字
        for (int n : nums) {
            if (n <= k) {
                have += k - n;//较小数,可以算入承载量
            } else {
                if (have < n - k) return 0;//承载不了了,该答案不可行
                else have -= (n - k);//减去承载量
            }
        }
        return 1;
    }

    int minimizeArrayValue(vector &nums) {
        int left = 0, right = *max_element(nums.begin(), nums.end());
        while (left < right) {//二分答案,寻找最大值
            int mid = left + (right - left) / 2;
            if (check(nums, mid)) right = mid;
            else left = mid + 1;
        }
        return left;
    }
};

cg

贪心方法

  • 如果数组中只有一个元素,那么最大值为nums[0]。
  • 如果有两个数则为 { 两个数的均值 ( 和除 2 ) , n u m [ 0 ] < n u m s [ 1 ] n u m [ 0 ] , n u m [ 0 ] < n u m s [ 1 ] \left\{\begin{array}{l}两个数的均值(和除2) ,num[0]{两个数的均值(和除2)num[0]<nums[1]num[0]num[0]<nums[1].
  • 如果有第三个值,其大于之前计算的值,那么可以进行“补贴”给前边的两个值,最终达到三个数的平均值,否则就是继续上一步计算得到的值。
  • 以此类推直到最后一个数。

转化为代码

class Solution {
public:
    int minimizeArrayValue(vector<int>& nums)
    {
        int dp = nums[0];
        long long sum = nums[0];
        for (int i = 1; i < nums.size(); i++) {
            sum += nums[i];
            int avg = sum / (i + 1) + (bool)(sum % (i + 1));
            if (avg > dp)  dp = avg;
        }
        return dp;
    }
};
  • https://blog.csdn.net/weixin_44179892/article/details/104197011
  • https://zhuanlan.zhihu.com/p/616523429

你可能感兴趣的:(笔记,算法)