题目描述
给你三个正整数 n、index 和 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] 满足所有条件。不存在其他在指定下标处具有更大值的有效数组。
解题思路
这道题一开始直接用暴力解决方案,定义一个变量h, 从1到maxSum;如果满足条件则 max = h> max ? h : max
这个思路一定能解决上述问题,但是时间复杂度是O(maxSum);
由于整个h值不断递增,并且最大是maxSum,这里可以使用二分查找:
- 准备left 和 right ,用于二分查找
- 在left < right的情况执行下面的逻辑
- 计算mid = (left+right+1)/2; 这个操作一定保证mid是不断上涨的
- 然后计算mid是否合法,如果合法则left=mid;否则right=mid - 1
- 最后返回left
代码实现
package main
func maxValue(n int, index int, maxSum int) int {
// left建议用1,不要用0
left := 1
right := maxSum
for left < right {
// 这个地方没想明白,为啥要加+1才OK
// left = 2
// right = 3
// mid = (right+left)/2=2
// mid = (right+left+1)/2 = 3
// 这样才能避免死循环
mid := (right + left + 1) / 2
if valid(mid, maxSum, index, n) {
left = mid
} else {
right = mid - 1
}
}
return left
}
func valid(h int, maxSum int, index int, n int) bool {
sum := cal(h, 0, index-1) + cal(h, index+1, n-1) + h
return sum <= maxSum
}
func cal(h int, start int, end int) int {
if start > end {
return 0
}
if (h - 1) > (end - start + 1) {
return (end - start + 1) * (h - 1 + (h - (end - start + 1))) / 2
} else {
return (h)*(h-1)/2 + ((end - start + 1) - (h - 1))
}
}
func main() {
}
总结
这道题一开始我没有读懂题目,后续看题解才明白要解决啥问题;整体实现上直接使用二分查找就能解决;最近在学golang,所以代码实现也切换成golang;代码执行效果如下: