题目:
给你三个正整数 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 。
0不是正整数!
思考:
首先确定数组是要由我自己构造的,也就是说我要创造一个数组,向其中填充数据,并且使这个数组满足题目需求。
向其中填充数据这一部分可以通过随机生成数字来向其中填充,并根据获得的参数n来限制数组长度
例如:
Math.floor(Math.random()*100+1) 是获得1到一百的随机整数
那么:
Math.floor(Math.random()*n+1) 就是获取1到n之间的随机整数
那么通过:
function arr(n) {
var num = new Array(n).fill("");
for (let i = 0; i < n; i++) {
num[i] = Math.floor(Math.random() * n + 1);
}
console.log(num);
}
就得到了一个长度为n且每个元素的值都小于n的数组
好吧事实上当我做到这一步已经不知道该如何完成其他要求了😥(补:因为直到这里的思路都不对当然做不出来😅)
学习:
这道题关于js的解法还挺少的
根据官方给出的解决方法来理解一下:
贪心 + 二分查找
思路
根据题意,需要构造一个长度为 n 的数组 nums,所有元素均为正整数,元素之和不超过 maxSum,相邻元素之差不超过 1,且需要最大化 nums[index]。根据贪心的思想,可以使 nums[index] 成为数组最大的元素,并使其他元素尽可能小,即从 nums[index] 开始,往左和往右,下标每相差 1,元素值就减少 1,直到到达数组边界,或者减少到仅为 1 后保持为 1不变。
根据这个思路,一旦 nums[index] 确定后,这个数组的和 numsSum 也就确定了。并且 nums[index] 越大,数组和 numsSum 也越大。据此,可以使用二分搜索来找出最大的使得numsSum≤maxSum 成立的 nums[index]。
代码实现上,二分搜索的左边界为 1,右边界为 maxSum。函数 valid 用来判断当前的 nums[index] 对应的 numsSum 是否满足条件。numsSum 由三部分组成,nums[index],nums[index] 左边的部分之和,和 nums[index] 右边的部分之和。cal 用来计算单边的元素和,需要考虑边界元素是否早已下降到 1 的情况。
var maxValue = function (n, index, maxSum) {
let left = 1,
right = maxSum;
while (left < right) {
const mid = Math.floor((left + right + 1) / 2); //这里的mid就是贪心法和二分法所得出的被作为中心的那个元素,体现二分法
if (valid(mid, n, index, maxSum)) {//返回值为真就进一步缩小左边范围
left = mid;
} else {
right = mid - 1;//返回值为假则缩小右边范围
}
}
return left;
};
const valid = (mid, n, index, maxSum) => {
let left = index; //令左边界,也就是第一个元素作为最大化的下标值,而且由于index越大数组和就越大,也就是说index越靠左,就越大,所以尽可能的令index成为左边界
let right = n - index - 1; //这里应该是得出右边界的下标值,但是不知道为什么这么写
return mid + cal(mid, left) + cal(mid, right) <= maxSum;//这里看懂了,验证数组和是否小于maxsum
};
const cal = (big, length) => {
//计算单边元素和
//因为abs(nums[i] - nums[i+1]) <= 1 ,可以得出相邻两个数的最大差值为一,或者元素干脆直接相等
if (length + 1 < big) {
const small = big - length;
return Math.floor(((big - 1 + small) * length) / 2);//这里看起来有点像梯形的上底乘下底乘以高再除以二,看不懂不知道为啥这么算
} else {
const ones = length - (big - 1);
return Math.floor((big * (big - 1)) / 2) + ones;//同样的也看不懂这里怎么算
}
};
console.log(maxValue(4, 2, 6));//2
中等题对我来说还是挺难的,根本摸不着头脑,也许以后会懂吧😢