每日一题——有界数组中指定下标处的最大值

226 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 11 天,点击查看活动详情


1802. 有界数组中指定下标处的最大值

给你三个正整数 nindex 和 maxSum 。你需要构造一个同时满足下述所有条件的数组 nums(下标 从 0 开始 计数):

  • nums.length == n
  • nums[i] 是 正整数 ,其中 0 <= i < n
  • abs(nums[i] - nums[i+1]) <= 1 ,其中 0 <= i < n-1
  • nums 中所有元素之和不超过 maxSum
  • nums[index] 的值被 最大化

返回你所构造的数组中的 nums[index] 。

注意:abs(x) 等于 x 的前提是 x >= 0 ;否则,abs(x) 等于 -x 。

 

示例 1:

输入: n = 4, index = 2,  maxSum = 6
输出: 2
解释: 数组 [1,1,2,1][1,2,2,1] 满足所有条件。不存在其他在指定下标处具有更大值的有效数组。

示例 2:

输入: n = 6, index = 1,  maxSum = 10
输出: 3

 

提示:

  • 1 <= n <= maxSum <= 109
  • 0 <= index < n

思路

对于这类题目,很难通过模拟的方式来解决,尝试考虑所有的可能方法是不现实的,遍历所有情况耗时过大,对于这种问题,可以换一种思路,使用二分法来降低耗时。

要求下标处的元素值最大,需要保证两侧的值尽可能的小,即由中间向两侧递减,这样才能保证中间值是最大的,我们可以想到的,index 下标处的值是有范围的,最小值为 1,最大值也不会超过 maxSum,故二分的上下界可以确定下来。若判定总和未超过 maxSum,则可以增大下界,否则减小上界。

在判定时,我们需要求得下标左右两侧的递减和,若依次遍历求得,则会超时,故需要使用递减公式,同时保证最小的值是正整数即可。

题解

class Solution {
    public int maxValue(int n, int index, int maxSum) {
        long low = 1, high = maxSum;
        while(low <= high) {
            long mid = low + ((high - low) >> 1);
            long sum = getSum(mid, index + 1);
            sum += getSum(mid, n - index) - mid;
            if(sum > maxSum) {
                high = mid - 1;
            }else {
                low = mid + 1;
            }
        }
        return (int) high;
    }

    private long getSum(long val, int length) {
        if(val >= length) {
            return (val + val - length + 1) * length / 2;
        }else {
            return (val + 1) * val / 2 + length - val;
        }
    }
}