哈希表简介:
(1)哈希表是一个存储数据的容器,
(2)哈希表的作用:'快速'查找某个元素
(3)哈希表使用的范围:当频繁想查找某个元素时,这个时候就可以用哈希表
(4)哈希表使用的方法:1.任何一门高级语言都有哈希表这一个容器2.用数组模拟一个简易哈希表
下面通过几个实例来给大家分析哈希表如何运用在算法中:
两数之和
题目

思路
我们不从当前数字出发去寻找它的另一半,而是反过来思考:我需要什么样的数字才能凑成目标?遍历数组时,我们一边走一边记录见过的数字,每遇到一个新数字,就快速查看它的"另一半"(target - 当前数)是否在之前的记录中出现过。如果出现过,立即返回这对组合的下标;如果没出现过,就把当前数字存入记录,继续向前探索。这样,原本需要双重循环O(n²)的搜索问题,就变成了只需一次遍历O(n)的"查字典"游戏。
解法
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target)
{
unordered_map<int,int> hash;
for(int i = 0;i < nums.size();i++)
{
int x = target - nums[i];
if(hash.count(x))
{
return {hash[x],i};
}
hash[nums[i]] = i;
}
return {0,0};
}
};
判断是否互为字符重排
题目

思路
我们可以把字符串 s1看作仓库初始库存,在哈希表中记录每个字符的"存货数量"。然后,遍历第二个字符串 s2时,每个字符就像是从仓库取货,对应字符的库存减一。最后检查仓库是否被恰好清空------如果所有字符的库存都归零,说明两个字符串的字符组成完全一致,只是排列顺序不同;如果有些字符库存有余或不足,则说明它们无法通过重排互相转换。
解法
class Solution {
public:
bool CheckPermutation(string s1, string s2)
{
vector<int> arr1(26,0);
int size1 = s1.size();
int size2 = s2.size();
if(size1 != size2)
{
return false;
}
for(int i = 0;i < size1;i++)
{
char ch = s1[i];
int x = ch - 97;
arr1[x]++;
}
for(int j = 0;j < size2;j++)
{
char ch = s2[j];
int x = ch - 97;
arr1[x]--;
if(arr1[x] < 0)
{
return false;
}
}
return true;
}
};
存在重复元素I
题目

思路
我们可以利用哈希表,仅需存储数「组内的元素」。在遍历数组的时候,⼀边检查哈希表中是否 已经出现过当前元素,⼀边将元素加⼊到哈希表中。如果某个数字重复出现,那么就返回true,如果遍历完整个数组没有重复出现,那么就返回false。
解法
class Solution {
public:
bool containsDuplicate(vector<int>& nums)
{
unordered_set<int> hash;
for(int i = 0;i < nums.size();i++)
{
if(hash.count(nums[i]))
{
return true;
}
hash.insert(nums[i]);
}
return false;
}
};
存在重复元素II
题目

思路
遍历数组时将当前元素和下标存入哈希表,若遇到重复元素,则比较当前下标与哈希表中记录的下标差值是否满足条件。如果满足条件则立即返回结果;否则,用当前下标覆盖 哈希表中旧的下标------因为下标递增,旧下标不可能与未来相同元素匹配得更近。这样既保证了查找的实时性,又通过不断"淘汰"过时的下标,确保了匹配的总是最近的相同元素,从而高效判断是否存在满足条件的索引对。
解法
class Solution {
public:
bool containsNearbyDuplicate(vector<int>& nums, int k)
{
unordered_map<int,int> hash;
for(int i = 0;i < nums.size();i++)
{
if(hash.count(nums[i]))
{
if(i - hash[nums[i]] <= k)
{
return true;
}
else
{
hash[nums[i]] = i;
}
}
hash[nums[i]] = i;
}
return false;
}
};