day124—二分查找—最小化数组中的最大值(LeetCode-2439)

题目描述

给你一个下标从 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

解决方案:

问题目标

给定一个数组,可以通过操作(将某个元素减1,同时将其左侧相邻元素加1)来调整数组,目标是最小化调整后数组的最大值

算法框架

1. 核心思想:二分查找答案

  • 我们不知道最小化的最大值是多少,但可以猜测一个值

  • 如果猜测值太小,无法通过操作使所有元素不超过它

  • 如果猜测值足够大,总能满足要求

  • 使用二分查找找到最小的满足条件的值

2. 二分查找部分

  • left 初始为 -1(确保答案比它大)

  • right 初始为数组最大值(这是肯定可行的上限)

  • 不断二分,检查中间值 mid 是否可行

  • 最终 right 就是最小可行值

3. 关键:check 函数(贪心验证)

检查给定限制 limit 是否可行:

  • 右向左遍历数组(因为只能向左传递数值)

  • 维护 dx 变量:表示需要向左传递的"超额"部分

  • 对于每个位置 i,计算当前值加上传递来的值

  • 如果超过 limit,超额部分继续向左传递

  • 最后检查第一个元素加上传递来的值是否不超过 limit

直观例子

假设 nums = [3, 7, 1, 6]limit = 5

  • 从右向左处理:

    • i=3: 6 ≤ 5? false,超额1传递给左边

    • i=2: 1 + 1 = 2 ≤ 5,无超额

    • i=1: 7 ≤ 5? false,超额2传递给左边

    • i=0: 3 + 2 = 5 ≤ 5,可行

算法特点

  • 时间复杂度:O(n log M),其中M是数组最大值

  • 空间复杂度:O(1)

  • 利用了单调性:如果limit可行,那么更大的limit也一定可行

  • 贪心策略最优:从右向左尽量传递超额值是最有效的

函数源码:

cpp 复制代码
class Solution {
public:
    bool check(vector<int>nums,int limit){
        long long dx=0;
        for(int i=nums.size()-1;i>0;i--){
            long long newNum=nums[i]+dx;
            dx=max(newNum-limit,0LL);
        }

        return nums[0]+dx<=limit;
    }

    int minimizeArrayValue(vector<int>& nums) {
        int max=*max_element(nums.begin(),nums.end());
        int left=-1;
        int right=max;

        while(left+1<right){
            int mid=(left+right)/2;
            if(check(nums,mid)){
                right=mid;
            }else{
                left=mid;
            }

        }
        return right;
    }
};
相关推荐
罗湖老棍子3 分钟前
【例9.18】合并石子(信息学奥赛一本通- P1274)从暴搜到区间 DP:石子合并的四种写法
算法·动态规划·区间dp·区间动态规划
2301_8107301012 分钟前
python第四次作业
数据结构·python·算法
adam_life15 分钟前
区间动态# P1880 [NOI1995] 石子合并】
算法
坠金20 分钟前
递归、递归和回溯的区别
算法
恋爱绝缘体125 分钟前
Java语言提供了八种基本类型。六种数字类型【函数基数噶】
java·python·算法
仰泳的熊猫30 分钟前
题目1434:蓝桥杯历届试题-回文数字
数据结构·c++·算法·蓝桥杯
星火开发设计33 分钟前
格式化输入输出:控制输出精度与对齐方式
开发语言·c++·学习·算法·函数·知识
ygklwyf39 分钟前
模拟退火算法零基础快速入门
数据结构·c++·算法·模拟退火算法
XX風40 分钟前
3.3 GMM (高斯混合模型)
人工智能·算法·机器学习
zy_destiny1 小时前
【工业场景】用YOLOv26实现8种道路隐患检测
人工智能·深度学习·算法·yolo·机器学习·计算机视觉·目标跟踪