今天继续来学习哈希表
题目1.四数相加II
题目链接:学透哈希表,map使用有技巧!LeetCode:454.四数相加II_哔哩哔哩_bilibili
关于如何选择集合/映射,可以参考以下表格
C代码(来源-->代码随想录)笔者仅作注释
// 哈希表大小
const int HASH_SIZE = 101;
//这里定义了哈希表的大小为101。选择一个质数作为哈希表的大小是一个常见的做法,因为质数可以减少哈希冲突的概率。
typedef struct node { //哈希表节点结构(node
)
/*
这里定义了一个结构体node
,它包含三个字段:val
存储哈希键的值,count
记录这个值出现的次数,next
是指向下一个node
的指针,用于处理哈希冲突。
*/
int val;
int count;
struct node *next;
} node, *HashMap;
// 哈希表插入
void hash_insert(HashMap hashmap[], int val) {
/*这个函数负责将给定的值val
插入到哈希表中。首先,它计算val
的哈希索引(考虑到负数情况),然后在相应的链表中查找该值。如果找到,就增加其计数;如果没有找到,就在链表末尾添加一个新的节点。
*/
int idx = val < 0 ? (-val) % HASH_SIZE : val % HASH_SIZE, count = 0;
node *p = hashmap[idx];
while (p->next != NULL) {
p = p->next;
if (p->val == val) {
(p->count)++;
return;
}
}
node *new = malloc(sizeof(node));
new->val = val;
new->count = 1;
new->next = NULL;
p->next = new;
return;
}
// 哈希表查找
int hash_search(HashMap hashmap[], int val) {
int idx = val < 0 ? (-val) % HASH_SIZE : val % HASH_SIZE;
node *p = hashmap[idx];
while (p->next != NULL) {
p = p->next;
if (p->val == val) return p->count;
}
return 0;
}
int fourSumCount(int* nums1, int nums1Size, int* nums2, int nums2Size, int* nums3, int nums3Size, int* nums4, int nums4Size){
// 初始化哈希表
HashMap hashmap[HASH_SIZE];
for (int i = 0; i < HASH_SIZE; i++) {
hashmap[i] = malloc(sizeof(node));
hashmap[i]->next = NULL;
}
// 统计两个数组元素之和的负值和出现的次数,放到哈希表中
int count = 0, num;
for (int i = 0; i < nums1Size; i++) {
for(int j = 0; j < nums2Size; j++) {
num = - nums1[i] - nums2[j];
hash_insert(hashmap, num);
}
}
// 统计另外两个数组元素之和,查找哈希表中对应元素的出现次数,加入总次数
for (int i = 0; i < nums3Size; i++) {
for(int j = 0; j < nums4Size; j++) {
num = nums3[i] + nums4[j];
count += hash_search(hashmap, num);
}
}
return count;
}
小结:它初始化一个哈希表,并遍历nums1
和nums2
的所有元素对,计算它们的和的负值,并将这些负值及其出现次数存储在哈希表中。然后,它遍历nums3
和nums4
的所有元素对,计算它们的和,并在哈希表中查找这个和的相反数的出现次数(即查找在哈希表中之前存储的负值)。最后,它将所有找到的匹配次数累加,并返回这个总和。
Python代码
一开始就想到用字典的思路了,使用python做本题有油然而生的爽快感,毕竟个人认为python代码比C简单多了, 虽然思路大致相似。
class Solution(object):
def fourSumCount(self, nums1, nums2, nums3, nums4):
# 使用字典存储nums1和nums2中的元素及其和
hashmap = dict()
for n1 in nums1:
for n2 in nums2:
hashmap[n1+n2] = hashmap.get(n1+n2, 0) + 1
# 如果 -(n1+n2) 存在于nums3和nums4, 存入结果
count = 0
for n3 in nums3:
for n4 in nums4:
key = - n3 - n4
if key in hashmap:
count += hashmap[key]
return count
题目2.383. 赎金信
Python代码
代码思路比较简单、清晰,可供读者参考,内存占用这块我还是很有自信的。
# 使用两个字典分别记录 ransomNote 和 magazine 中字符的出现次数
dict1 = {}
dict2 = {}
# 遍历 ransomNote,记录每个字符的出现次数
for char in ransomNote:
dict1[char] = dict1.get(char, 0) + 1
# 遍历 magazine,记录每个字符的出现次数
for char in magazine:
dict2[char] = dict2.get(char, 0) + 1
# 检查 ransomNote 中的每个字符是否在 magazine 中有足够的数量
for char, count in dict1.items():
# 如果字符不存在于 magazine 的字典中,或者数量不足,则返回 False
if char not in dict2 or dict2[char] < count:
return False
# 如果所有字符都检查通过,则返回 True
return True
另外附两个其他版本的代码:
C代码
bool canConstruct(char* ransomNote, char* magazine) {
int hashmap[26] = {0};
//首先我们要获取magezine字符串中每个字符的出现频率
while (*magazine != '\0'){
hashmap[*magazine++ % 26]++;
}
// 遍历ransomNote,对应的字符自减,小于0说明该字符magazine没有或不足够表示
while (*ransomNote != '\0'){
hashmap[*ransomNote++ % 26]--;
}
// 如果数组中存在负数,说明ransomNote不能由magazine里面的字符构成
for (int i = 0; i < 26; i++) {
if (hashmap[i] < 0) return false;
}
return true;
}
题目3. 三数之和
梦破碎的地方!| LeetCode:15.三数之和_哔哩哔哩_bilibili
#此处应有夢消失 ~Lost Dream - Demetori - 单曲 - 网易云音乐
python代码
nums.sort() # 先对数组进行排序,有助于减少不必要的搜索
res = []
n = len(nums)
for i in range(n-2): # 只需要遍历到倒数第三个元素
if i > 0 and nums[i] == nums[i-1]: # 跳过重复的元素
continue
left, right = i+1, n-1
while left < right:
total = nums[i] + nums[left] + nums[right]
if total < 0:
left += 1
elif total > 0:
right -= 1
else:
res.append([nums[i], nums[left], nums[right]])
# 移动左右指针,并跳过重复的元素
while left < right and nums[left] == nums[left+1]:
left += 1
while left < right and nums[right] == nums[right-1]:
right -= 1
left += 1
right -= 1
return res
C代码:
歇菜了
小结:使用双指针法来优化性能,通过排序和跳过重复元素来减少不必要的计算。同时,确保添加到 res
中的是具体的元素值而不是索引。
总结:
笔者C语言基础还不够扎实,很多代码反而是使用python完成的,要加强对C语言指针、哈希表的运用。