一、题目描述
1.题目内容
大餐是指恰好包含两道不同餐品的一餐,其美味程度之和等于 2 的幂。
你可以搭配任意两道餐品做一顿大餐。
给你一个整数数组 deliciousness ,其中 deliciousness[i] 是第 i 道餐品的美味程度,返回你可以用数组中的餐品做出的不同大餐的数量。结果需要对 109 + 7 取余。
注意,只要餐品下标不同,就可以认为是不同的餐品,即便它们的美味程度相同。
2.题目示例
示例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) 。
3.提示
1 <= deliciousness.length <= 105
0 <= deliciousness[i] <= 220
二、思路
思路1
排序双指针。
对于每个2的幂数进行双指针遍历,得到相应的数量。这其中需要注意的是将每次对应的数的一半单独提出来计数,因为这部分数据前后两个指针指向的数字相同,不能直接计数。
思路2
哈希表。
边遍历边添加边查找。
每次遍历判断是否有对应的数,在哈希表中查找。
如果有,则将能组合的次数添加进结果
如果没有,那就没有呗,无需进行操作
三、数据结构资料
请参考笔者总结的有关于本题所需使用的数据结构资料:
Java HashMap
四、代码
代码1
class Solution
{
public int countPairs(int[] deliciousness)
{
ArrayList<Integer> de = new ArrayList<Integer>();
for(int number : deliciousness)
{
de.add(number);
}
Collections.sort(de);
int i;
long count = 0;
int pow = 1;
for(i = 0; i < 22; i++)
{
count += countNumber(de, pow);
pow *= 2;
}
count %= 1000000007;
return (int)count;
}
private static long countNumber(ArrayList array, int sum)
{
int start = 0;
int end = array.size() - 1;
if((int)array.get(start) > sum)
{
return 0;
}
long count = countHalfOfSumMatches(array, sum);
while(start < end)
{
if ((int)array.get(start) + (int)array.get(end) > sum)
{
end--;
}
else if ((int)array.get(start) + (int)array.get(end) < sum)
{
start++;
}
else
{
if((int)array.get(start) == (int)array.get(end))
{
break;
}
int startElement = (int)array.get(start);
int equalStartElements = 1;
while (start + 1 < end && (int)array.get(start + 1) == startElement)
{
equalStartElements++;
start++;
}
int endElement = (int)array.get(end);
int equalEndElements = 1;
while (end - 1 > start && (int)array.get(end - 1) == endElement)
{
equalEndElements++;
end--;
}
count += equalStartElements * equalEndElements;
start++;
end--;
}
}
return count;
}
private static long countHalfOfSumMatches(ArrayList array, int sum)
{
if(sum == 1)
{
return 0;
}
long count = 0;
int temp = sum / 2;
for (int i = 0;i < array.size();i++)
{
if ((int)array.get(i) == temp)
{
count++;
}
}
count = (count * (count - 1))/2;
return count;
}
}
代码2
class Solution
{
public int countPairs(int[] deliciousness)
{
Map<Integer, Integer> map = new HashMap<>();
Long result = 0L;
int length = deliciousness.length;
for (int num : deliciousness)
{
int pow = 1;
for (int i = 0; i <= 21; i++)
{
if (pow >= num && map.containsKey(pow - num))
{
result += map.get(pow - num);
}
pow *= 2;
}
map.put(num, map.getOrDefault(num, 0) + 1);
}
return (int)(result % 1000000007);
}
}
五、复杂度分析
时间复杂度O(n)
空间复杂度O(n)
思路 | 思路1 | 思路2 |
---|---|---|
执行用时 | 109ms | 107ms |
时间击败比例 | 75% | 75% |
内存消耗 | 47.4MB | 53.6MB |
内存击败比例 | 53% | 14% |