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

文章介绍了如何在给定数组中通过特定操作最小化数组的最大值,提出了二分答案和贪心方法两种策略。二分答案适用于寻找满足特定条件的最大或最小值,而贪心方法则按顺序考虑数组元素,尝试逐步优化。
  • mid : 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

二分答案

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

  • 具体实现时,可以先定义一个判断函数,用于判断当前答案是否符合条件。然后根据题目要求,确定答案范围,比如可以将答案范围设为 [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.(PS:二分答案有些像零知识证明的验证方法)

class Solution {
public:
    static bool check(vector<int> &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<int> &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]<nums[1]\\num[0],num[0]<nums[1] \end{array}\right. {两个数的均值(和除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;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值