题目
1711. 大餐计数
https://leetcode-cn.com/problems/count-good-meals/
大餐 是指 恰好包含两道不同餐品 的一餐,其美味程度之和等于 2 的幂。
你可以搭配 任意 两道餐品做一顿大餐。
给你一个整数数组 deliciousness
,其中 deliciousness[i]
是第 i
道餐品的美味程度,返回你可以用数组中的餐品做出的不同 大餐 的数量。结果需要对 109 + 7
取余。
注意,只要餐品下标不同,就可以认为是不同的餐品,即便它们的美味程度相同。
示例 1:
输入:deliciousness = [1,3,5,7,9]
输出:4
解释:大餐的美味程度组合为 (1,3) 、(1,7) 、(3,5) 和 (7,9) 。
它们各自的美味程度之和分别为 4 、8 、8 和 16 ,都是 2 的幂。
示例 2:
输入:deliciousness = [1,1,1,3,3,3,7]
输出:15
解释:大餐的美味程度组合为 3 种 (1,1) ,9 种 (1,3) ,和 3 种 (1,7) 。
提示:
1 <= deliciousness.length <= 105
0 <= deliciousness[i] <= 220
题解
思路
哈希,存储出现过的数字次数,如果有出现则加上出现的次数。先计算出2的前22个幂的值,然后用减法,从哈希中获取是否有存在值。时间复杂度是O(n*22)
代码
/**
* @param {number[]} deliciousness
* @return {number}
*/
// 提前计算前21个值
const pow = [];
for (let i = 0; i <= 21; i++) {
pow.push(2 ** i);
}
var countPairs = function (deliciousness) {
const n = deliciousness.length;
const MOD = 10 ** 9 + 7;
let hash = new Map();
// 把数组第一个加到哈希中
hash.set(deliciousness[0], 1)
let ans = 0;
let res;
// 数组从1开始
for (let i = 1; i < n; i++) {
// 对前21个值进行遍历,如果有在hash中出现过,那就加上该值出现过的次数
for (let j = 0; j <= 21; j++) {
res = pow[j] - deliciousness[i];
if (hash.has(res)) {
ans = (ans + hash.get(res)) % MOD;
}
}
// 判断完之后,把当前值加到hash中
hash.set(deliciousness[i], (hash.get(deliciousness[i]) || 0) + 1)
}
return ans;
};