一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第11天,点击查看活动详情。
说明:文章部分内容及图片出自网络,如有侵权请与我本人联系(主页有公众号:小攻城狮学前端)
作者:小只前端攻城狮、 主页:小只前端攻城狮的主页、 来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
【LeetCode 1648. 销售价值减少的颜色球 】- JavaScript(贪心+二分)
题意描述
你有一些球的库存 inventory ,里面包含着不同颜色的球。一个顾客想要 任意颜色 总数为 orders 的球。
这位顾客有一种特殊的方式衡量球的价值:每个球的价值是目前剩下的 同色球 的数目。比方说还剩下 6 个黄球,那么顾客买第一个黄球的时候该黄球的价值为 6 。这笔交易以后,只剩下 5 个黄球了,所以下一个黄球的价值为 5 (也就是球的价值随着顾客购买同色球是递减的)
给你整数数组 inventory ,其中 inventory[i] 表示第 i 种颜色球一开始的数目。同时给你整数 orders ,表示顾客总共想买的球数目。你可以按照 任意顺序 卖球。
请你返回卖了 orders 个球以后 最大 总价值之和。由于答案可能会很大,请你返回答案对 109 + 7 取余数 的结果。
示例 1:
输入:inventory = [2,5], orders = 4 输出:14 解释:卖 1 个第一种颜色的球(价值为 2 ),卖 3 个第二种颜色的球(价值为 5 + 4 + 3)。 最大总和为 2 + 5 + 4 + 3 = 14 。
示例 2:
输入:s = "aaabbbcc" 输出:2 解释:可以删除两个 'b' , 得到优质字符串 "aaabcc" 。 另一种方式是删除一个 'b' 和一个 'c' ,得到优质字符串 "aaabbc" 。
思路分析:
第一眼看完题目,想到的就是贪心
只要每次都卖出剩下同色球数目最多的球,就能够得到卖了但是二分的下界不好判断。需要好好想一下。不能蛮上,不然只能一直Wa~orders个球之后最大总价值之和。但是贪心可能不够快,发现题目还是满足二分的
二分查找
我们把整个过程想象成整组数字从上到下一层一层的取,直到取到orders数量为止。把我们可以取到的最小的数字进行做二分法,如果数列中这个数字这个数字以上的部分全部取完小于orders说明还要取更小的数字,否则需要取得更大的数字。答案很可能存在于两层之间,也就是这一层取完大于orders,上一层取完小于orders,所以验证时同时计算两层。
注意: 不过这里有一个坑,如果当前最低价值计算可获取订单数量小于预订订单数量时,需要将最低价值-1,继续遍历数组累加利润,直到可获取订单数量==预订订单数量,这样得到的才是最大利润。
var maxProfit = function(inventory, orders) {
const mod = BigInt(1e9 + 7);
inventory.sort((a, b) => (b - a));
let l = 0, r = 1e9, len = inventory.length;
while (l < r) {
let mid = Math.floor((l + r) / 2), sum_ball = 0;
for (let i = 0; i < len; i++) {
sum_ball += Math.max(0, inventory[i]-mid+1);
if (sum_ball > orders) break;
}
if (sum_ball < orders) {
r = mid;
} else {
l = mid + 1;
}
}
let res = 0n, sum_ba = 0;
for (let i = 0; i < len; i++) {
if (inventory[i] >= l) {
res += BigInt(inventory[i]+ l) * BigInt(inventory[i] - l + 1) / 2n ;
sum_ba += (inventory[i] - l + 1);
// res %= mod;
} else {
break;
}
}
res += BigInt((orders - sum_ba) * (l - 1)) ;
return res % mod;
};
贪心
思路:
贪心策略就是选择当前最大的值,并且每轮都选择当前最大值,最后也能得到最优解。这可以想到可以用优先队列每次取出最大的值,然后减去1再放回队列,由于值最大是1e9,这样的做法是超时的,所以需要考虑优化减1这个迭代的过程,即当前值最终会变成什么值。
具体:将库存inventory按降序排列,依次取价值最大的球,直到不能取为止。
var maxProfit = function (inventory, orders) {
inventory.sort((a, b) => b - a)
let i = 0
let res = BigInt(0)
let min = 0
let flag = true
while (flag) {
while (inventory[i] === inventory[i + 1]) {
i++
}
let v = (inventory[i] - inventory[i + 1]) * (i + 1)
if (orders > v && i < inventory.length - 1) {
orders -= v
i++
} else {
let n = Math.floor(orders / (i + 1))
min = inventory[i] - n
orders -= n * (i + 1)
flag = false
}
}
while (i >= 0) {
res += geth(inventory[i], inventory[i] - min)
i--
}
return (res + BigInt(orders * min)) % BigInt(1e9 + 7)
};
function geth(num, orders) {
return BigInt(num + num - orders + 1) * BigInt(orders) / BigInt(2) % BigInt(1e9 + 7)
}
感谢阅读,希望能对你有所帮助,文章若有错误或者侵权,可以在评论区留言或在我的主页添加公众号联系我。
写作不易,如果觉得不错,可以「点赞」+「评论」 谢谢支持❤