【Leecode1802】有界数组中指定下标处的最大值

题目:

给你三个正整数 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

中等题对我来说还是挺难的,根本摸不着头脑,也许以后会懂吧😢

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值