哈希表
哈希表中的常见使用情景,判断一个元素是否曾经出先在某个容器里。当需要用的容器较小时一般用数组。
1、有效的字母异位同
判断两个单词的字母的组成是否相同,如 rt 和 tr ?
思路:哈希表一般用数组,set 或 map。那么只要用数组就行 a[26] 。最简单的使用for循环,第一次for循环把每个字母的位置+1,第二次for循环则-1。
伪代码:
int hash[26] = 0;
for(i = 0; i < s.size; i++)
hash[s[i] - 'a']++;
for(i = 0; i < t.size; i++)
hash[s[i] - 'a']--;
for(i = 0; i < 26; i++)
if(hash[i] != 0)
return false;
return true;
2、求两个数组的交集
一个数组为 9 9 8,另一给数组为 4 3 9,其交集为9
一般使用unorder_set来作为容器。unorder_set类型的数据结构会自动去重。
unorder_set result;
unorder_set num_set(nums1);
for(i = 0; i < num2.size; i++)
{
if(num_set.find(num2[i]) != num_set.end(1))
result.insert(nums2[i]);
}
return vector(result.array);//将set转换为数组
C ++ set find()函数用于查找具有给定值 val 的元素。如果找到元素,则返回指向该元素的迭代器,否则返回指向集合末尾的迭代器,即set :: end()。
3、两数之和
给一个数组,给一个目标值,要找到两个元素的和等于这个目标值,返回值为下标,如果有多对,那么只需要返回一个
map解题过程:
map存放遍历过的元素,其中key存放数组元素,value存放数组索引。为什么?
因为key不允许重复。
伪代码:
unordered_map<int,int> map1;
int nums[] = {2,4,7,9};
int target = 9;
for(i = 0; i < nums.size; i++)
{
s = target - nums[i];
//检查这个s是否在之前出现过
iter = map1.find(s);
if(iter != map1.end())
{
//如果出现过,直接返回
return {iter->value,i};
}
//如果没有出现,则把此时的元素添加到map里
map1.insert(nums[i],i);
}
如果不知道iter是什么类型,直接用auto。map的插入方法:map1.insert(pair<int,int>(1,2))。iter->first取键值,iter->second取值。
4、四数相加
给定四个数组,在这四个数组中分别找到一个元素能使得这四个数相加为零,求总共有几组元素:
思路:
把A数组和B数组各元素相加,形成一个长度为 n 2 n^2 n2的数组,再把C数组和D数组各元素相加,形成一个长度为 n 2 n^2 n2的数组。不仅要统计是否出现过,还要统计出现过的次数,此时需要的就算map。然后这个问题就转换为了一个两数之和的问题:
伪代码:
unordered_map<int,int> map1;
int count = 0;
for(a:A)
{
for(b:B)
{
map[a+b]++;
}
}
for(c:C)
{
for(d:D)
{
target = 0 - (c+d);
auto iter = map1.find(target);
if(iter = map1.end())
{
count = count + map1->second;
}
}
}
5、三数之和
在一个数组中找到 a + b + c = t a r g e t a+b+c=target a+b+c=target ,求一组 a 、 b 、 c a、b、c a、b、c的值,其中 t a r g e t target target 为正数。
伪代码:(核心是先排序定义left和right用来收缩)
sort(nums);
for(i = 0; i < nums.size; i++)
{
if(nums[i] > 0)
return 0;
else
{
if(nums[i] = nums[i-1]) continue;//去重
left = i + 1;
right = numsize - 1;
while(right > left)
{
if(nums[i] + nums[right] + nums[left] > 0)
right--;
else if
left++;
else
{
result.push();
while (right > left && nums[right] == nums[right - 1]) right--;//去重
while (right > left && nums[left] == nums[left + 1]) left++;//去重
left++;
right--;
//找到答案时,两个指针同时收缩
}
}
}
}
6、四数之和
在一个数组中找到四个数的和为target。
思路: 在三数之和的基础上再加一个k,如下图所示:
伪代码:
sort(nums);
for(k = 0; k < nums.size(); k++ )
{
if(nums[k] == nums[k-1]) continue;
else
{
for(i = k+1; i < nums.size; i++)
{
//{三数之和的代码类似}
}
}
}