[ 优先队列 ]6039. K 次增加后的最大乘积

208 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第10天,点击查看活动详情

每日刷题 2021.04.10

题目

  • 给你一个非负整数数组 nums 和一个整数 k 。每次操作,你可以选择 nums 中 任一 元素并将它 增加 1 。
  • 请你返回 至多 k 次操作后,能得到的 nums的 最大乘积 。由于答案可能很大,请你将答案对 10^9 + 7 取余后返回。

示例

  • 示例1
输入:nums = [0,4], k = 5
输出:20
解释:将第一个数增加 5 次。
得到 nums = [5, 4] ,乘积为 5 * 4 = 20 。
可以证明 20 是能得到的最大乘积,所以我们返回 20 。
存在其他增加 nums 的方法,也能得到最大乘积。
  • 示例2
输入:nums = [6,3,3,2], k = 2
输出:216
解释:将第二个数增加 1 次,将第四个数增加 1 次。
得到 nums = [6, 4, 3, 3] ,乘积为 6 * 4 * 3 * 3 = 216 。
可以证明 216 是能得到的最大乘积,所以我们返回 216 。
存在其他增加 nums 的方法,也能得到最大乘积。

提示

  • 1 <= nums.length, k <= 10^5
  • 0 <= nums[i] <= 10^6

解题思路

  • js的语法内,貌似没有优先队列这样的现成的数据结构,但是后面搜查到leetcode库中存在优先队列的数据结构。
    • 最小优先队列MinPriorityQueue
    • 最大优先队列MaxPriorityQueue
  • 根据数学知识可知,想要获得乘积的最大值,那么需要尽可能的将所有的边变得相等,差值最小。
  • 因此,想到了使用最小优先队列的做法,通过将nums中的所有数值,存入到优先队列中queue.enqueue(num)。后续每次只需要从最小优先队列中获取队列头部的元素queue.dequeue(),就是当前的所有数中的最小值,每次将获取到的数值+1后,再塞回到最小优先队列中,在k次操作后,一定是最大乘积。

注意

  • 取模的注意事项:res = res * element % mod;,最开始写成res *= element % mod;出错了,因为其会先运算模运算%,在运算*=,这样的话,模运算就没有起到效果,数据还是会因为很大而溢出。
  • 位运算:按位与的注意事项,按位与符号的优先级比较低,因此在写表达式的时候,最好按照顺序标记好,不然就会出错。

AC代码

var maximumProduct = function(nums, k) {
  let mod = 1000000000 + 7;
  let len = nums.length;
  const queue = new MinPriorityQueue();
  for (const num of nums) {
    queue.enqueue(num)
  }
  // console.log(queue)
  while(k != 0) {
    let {element} = queue.dequeue()
    element++;
    // console.log(element)
    queue.enqueue(element);
    k--;
  }
  let res = 1;
  while(queue.size() != 0) {
    let {element} = queue.dequeue()
    res = res * element % mod;
  }
  return res;
};

总结

  • 注意,1000000000 + 7js的代码中,可以直接书写1e9 + 7, 避免在书写0的时候出错,节省时间,更高效。