Medium
题目描述
给你三个正整数: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 的绝对值。
示例 1:
输入:n = 4, index = 2, maxSum = 6
输出:2
解释:数组 [1,2,2,1] 满足所有条件。
不存在其他满足所有条件且 nums[2] == 3 的数组,所以 2 是 nums[2] 的最大值。
示例 2:
输入:n = 6, index = 1, maxSum = 10
输出:3
约束条件:
- 1 <= n <= maxSum <= 10^9
- 0 <= index < n
解题思路
这道题要求构造一个有界数组,使得指定位置的值最大。关键观察是:为了最大化 nums[index],我们应该让数组以该位置为峰值,向两边递减。
核心思路:
- 贪心策略:以
index为中心构造一个"山峰"形数组,向左右两边递减,直到边界或者值为1 - 二分搜索:在可能的取值范围内二分查找最大的
nums[index] - 数学计算:对于给定的峰值,快速计算整个数组的最小和
算法流程:
- 二分搜索范围:
[1, maxSum] - 对于每个候选值
mid,计算以它为峰值时数组的最小和 - 如果和 ≤ maxSum,说明可行,尝试更大的值
- 否则说明太大,减小搜索范围
关键计算:
对于峰值 val,左右两部分的最小和可以用等差数列求和公式快速计算。例如左边部分:
- 如果
val > index + 1,和为val + (val-1) + ... + (val-index) - 否则部分为递减序列,部分为1
时间复杂度为 O(log(maxSum)),空间复杂度为 O(1)。
代码实现
class Solution {
public:
int maxValue(int n, int index, int maxSum) {
auto getSum = [&](long long val) -> long long {
long long sum = val;
// 计算左边部分的和
long long leftCount = index;
if (val > leftCount) {
sum += (val - 1 + val - leftCount) * leftCount / 2;
} else {
sum += (val - 1) * val / 2 + (leftCount - val + 1);
}
// 计算右边部分的和
long long rightCount = n - index - 1;
if (val > rightCount) {
sum += (val - 1 + val - rightCount) * rightCount / 2;
} else {
sum += (val - 1) * val / 2 + (rightCount - val + 1);
}
return sum;
};
int left = 1, right = maxSum;
int result = 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (getSum(mid) <= maxSum) {
result = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
return result;
}
};
class Solution:
def maxValue(self, n: int, index: int, maxSum: int) -> int:
def getSum(val):
total = val
# 计算左边部分的和
left_count = index
if val > left_count:
total += (val - 1 + val - left_count) * left_count // 2
else:
total += (val - 1) * val // 2 + (left_count - val + 1)
# 计算右边部分的和
right_count = n - index - 1
if val > right_count:
total += (val - 1 + val - right_count) * right_count // 2
else:
total += (val - 1) * val // 2 + (right_count - val + 1)
return total
left, right = 1, maxSum
result = 1
while left <= right:
mid = (left + right) // 2
if getSum(mid) <= maxSum:
result = mid
left = mid + 1
else:
right = mid - 1
return result
public class Solution {
public int MaxValue(int n, int index, int maxSum) {
long GetSum(long val) {
long sum = val;
// 计算左边部分的和
long leftCount = index;
if (val > leftCount) {
sum += (val - 1 + val - leftCount) * leftCount / 2;
} else {
sum += (val - 1) * val / 2 + (leftCount - val + 1);
}
// 计算右边部分的和
long rightCount = n - index - 1;
if (val > rightCount) {
sum += (val - 1 + val - rightCount) * rightCount / 2;
} else {
sum += (val - 1) * val / 2 + (rightCount - val + 1);
}
return sum;
}
int left = 1, right = maxSum;
int result = 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (GetSum(mid) <= maxSum) {
result = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
return result;
}
}
var maxValue = function(n, index, maxSum) {
const getSum = (val) => {
let sum = val;
// 计算左边部分的和
let leftCount = index;
if (val > leftCount) {
sum += (val - 1 + val - leftCount) * leftCount / 2;
} else {
sum += (val - 1) * val / 2 + (leftCount - val + 1);
}
// 计算右边部分的和
let rightCount = n - index - 1;
if (val > rightCount) {
sum += (val - 1 + val - rightCount) * rightCount / 2;
} else {
sum += (val - 1) * val / 2 + (rightCount - val + 1);
}
return sum;
};
let left = 1, right = maxSum;
let result = 1;
while (left <= right) {
let mid = Math.floor((left + right) / 2);
if (getSum(mid) <= maxSum) {
result = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
return result;
};
复杂度分析
| 复杂度 | 大小 |
|---|---|
| 时间复杂度 | O(log(maxSum)) |
| 空间复杂度 | O(1) |