开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 11 天,点击查看活动详情
1802. 有界数组中指定下标处的最大值
给你三个正整数 n、index 和 maxSum 。你需要构造一个同时满足下述所有条件的数组 nums(下标 从 0 开始 计数):
nums.length == nnums[i]是 正整数 ,其中0 <= i < nabs(nums[i] - nums[i+1]) <= 1,其中0 <= i < n-1nums中所有元素之和不超过maxSumnums[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 <= 1090 <= 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;
}
}
}