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;
    }
};
相关推荐
MediaTea2 小时前
AI 术语通俗词典:C4.5 算法
人工智能·算法
Navigator_Z2 小时前
LeetCode //C - 1033. Moving Stones Until Consecutive
c语言·算法·leetcode
WBluuue2 小时前
数据结构与算法:莫队(一):普通莫队与带修莫队
c++·算法
风筝在晴天搁浅3 小时前
n个六面的骰子,扔一次之后和为k的概率是多少?
算法
MATLAB代码顾问4 小时前
Python实现蜂群算法优化TSP问题
开发语言·python·算法
代码飞天4 小时前
机器学习算法和函数整理——助力快速查阅
人工智能·算法·机器学习
jiushiapwojdap4 小时前
LU分解法求解线性方程组Matlab实现
数据结构·其他·算法·matlab
笨笨饿5 小时前
69_如何给自己手搓一个串口
linux·c语言·网络·单片机·嵌入式硬件·算法·个人开发
纽扣6675 小时前
【算法进阶之路】链表进阶:删除、合并、回文与排序全解析
数据结构·算法·链表
消失的旧时光-19436 小时前
统一并发模型:线程、Reactor、协程本质是一件事(从线程到协程 · 第6篇·终章)
java·python·算法