提示:文章寫完後,目錄可以自動生成,如何生成可參考右邊的幫助文檔
5642. 大餐計數之哈希
前言
- 大餐計數之哈希O(1)
一、5642. 大餐計數之哈希O(1)
大餐 是指 恰好包含兩道不同餐品 的一餐,其美味程度之和等於 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,097提交次數11,846
二、 程序
1,會超時的哦
struct arrays
{
int value;
int count;
}arrays;
struct hashmap
{
struct arrays* table;
long long used;
long long size;
}hashmap;
bool Surplus(long long value)
{
int count = 0;
while (value>0 && count == 0)
{
if (value&1)
{
++count;
}
value = value>>1;
}
if (value>0)
{
return false;
}
return count == 1;
}
int countPairs1(int* deliciousness, int deliciousnessSize)
{
struct hashmap *map_ptr = malloc(sizeof(struct hashmap));
map_ptr->size = deliciousnessSize;
map_ptr->used = 0;
map_ptr->table = malloc(sizeof(struct arrays) * deliciousnessSize);
for (int i = 0; i < deliciousnessSize; ++i)
{
map_ptr->table[i].count = 0;
bool find = false;
int index = -1;
for (int j = 0; j < map_ptr->used; ++j)
{
if (map_ptr->table[j].value == deliciousness[i])
{
++map_ptr->table[j].count;
find = true;
break;
}
else if (map_ptr->table[j].value> deliciousness[i])
{
index = j;
++map_ptr->used;
for (int w = map_ptr->used ; w >j; --w)
{
map_ptr->table[w].value = map_ptr->table[w-1].value;
map_ptr->table[w].count = map_ptr->table[w-1].count;
}
break;
}
}
if (!find)
{
if (index != -1)
{
map_ptr->table[index].count = 1;
map_ptr->table[index].value = deliciousness[i];
}
else
{
map_ptr->table[map_ptr->used].count = 1;
map_ptr->table[map_ptr->used].value = deliciousness[i];
++map_ptr->used;
}
}
}
int count = 0;
for (int i = 0;i < map_ptr->used; ++i)
{
for (int j = i; j < map_ptr->used; ++j)
{
if (i !=j)
{
if (Surplus(map_ptr->table[i].value + map_ptr->table[j].value))
{
count += map_ptr->table[i].count * map_ptr->table[j].count;
}
}
else if (map_ptr->table[i].count>1)
{
if (Surplus(map_ptr->table[i].value + map_ptr->table[j].value))
{
count += ((map_ptr->table[i].count-1) * map_ptr->table[i].count) /2; //等差數列
}
}
}
}
if(map_ptr)
{
if(map_ptr->table)
{
free(map_ptr->table);
}
free(map_ptr);
}
long M = 1000000007;
return count%M;
}
2,利用目標2的冪技巧
①, 這邊爲什麼是22呢是因爲 2 21 2^{21} 221是最大值
②,比如: 1和什麼數相加是2的冪
那可以把這些數放到哈希表中查詢的時間複雜度就是 O ( 1 ) O(1) O(1)
③,科學計數法
1.什麼是 1 e 9 1e9 1e9
通常來說這是計算機中一種科學計數法的表示形式:
1 e 9 = 1 ∗ 1 0 9 = 1000000000 ; 1e9 = 1*10^9 = 1000000000; 1e9=1∗109=1000000000;
例如: 9 e 8 = 9 ∗ 1 0 8 = 900000000 ; 9e8 = 9*10^8 = 900000000; 9e8=9∗108=900000000;
e表示10,e後面的數字表示次方,e的多少次方。
2.C++中的 1 e 9 1e9 1e9
int n u m 1 = 1 e 9 ; { num1 = 1e9;} num1=1e9;
int n u m 1 = 1 e 10 ; {num1 = 1e10;} num1=1e10;
輸出的結果爲:
num1 = 1 000 000 000;
num2 = 1 410 065 408;
那麼問題來了,爲什麼num2 不等於 10000000000 ?
C/C++中int類型是32位的,範圍是-2147483648 到 2147483647。
int佔用4個字節,也就是32位,除了第一位代表符號,剩下的31位可用。
十進制的 1e10時,轉換爲二進制:
10 0101 0100 0000 1011 1110 0100 0000 0000前兩位出現數據溢出問題。
而0101 0100 0000 1011 1110 0100 0000 0000 轉換成十進制就是 1 410 065 408
int countPairs(int* deliciousness, int deliciousnessSize)
{
const int M = 1e9 + 7;
int hash[3000000]={
0}; //2的陪數 的差距保存哈希表
long long ans = 0;
for(int i = 0;i < deliciousnessSize; ++i)
{
//剛剛好是2的倍數
ans += hash[deliciousness[i]];
//距離 2的冪的距離統計個數 --》 這邊爲什麼是22呢是因爲2^21是最大值
for(int j = 0; j < 22; j++)
{
if(((1<<j)-deliciousness[i])>=0)
{
hash[(1<<j)-deliciousness[i]]++;
}
}
}
return ans % M;
}
時間複雜度 O ( 21 ∗ N ) O(21*N) O(21∗N)
空間複雜度 O ( 3000000 ) O(3000000) O(3000000)