哈希表
概念
哈希表也叫作散列表,是根据关键码值(key)而直接进行访问的数据结构,也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表.
散列表
我们先来认识一下一下散列表:
在记录的存储位置与该记录的关键值中间建立一种确定的对应关系,并使得每个记录的关键字值与结构中的一个唯一的储存位置相对应。这个关系会记录与当前关键字key相关的函数,也就是散列函数。只要根据这个对应关系就可以找到所要找到的记录。由于可能不同的关键字会得到相同的值,所以会造成散列冲突。我们分析题目就是要分析冲突的现象。
有以下几种构造方法
直接定址法
直接取关键字的某个函数作为散列函数,即H(k) = ak + b。其中,a , b 为常量,k为自变量
数字分析法
当关键字值的位数大于散列地址码的位数时,对关键字值的各个数字进行分析,从中取出和散列地址位数相同的数
平方取中法
计算关键值的平方,有目的的选取若干位作为散列地址
叠加法
移位叠加法和折叠叠加法
基数转换法
关键字值原来为十进制数,人为地当做q进制数,再转换成十进制作为散列地址
除留余数法
也就是取模法:对应的散列函数为H(k) = k MOD p。这个使用范围是最广的,也是最常用的构造散列函数的方法
随机数法
即产生一定范围内的随机数,散列函数为H(k) = random(k).random()为随机函数。
例题
看了这么多哈希表的知识,我们先来一道简单的题目。
给你一个字符串数组 words
,请你找出所有在 words
的每个字符串中都出现的共用字符( 包括重复字符),并以数组形式返回。你可以按 任意顺序 返回答案。
示例
输入:words = ["bella","label","roller"]
输出:["e","l","l"]
题目分析
题目中表明需要在world
数组中各个字符串之间都出现的公共字符。有的人就直接会想,我直接遍历不就好了吗,每个字符串遍历一下,找个公共字符串还不简单吗?显然这样子的代码不高效,且对于字符串的多种情况也不适用。而这里无疑是考虑字符出现的个数,也就是频率,所以我们这里考虑使用哈希表。而我们构造的哈希函数就是对应的26个字母。那么我们就定义一个hash[]
数组,先统计第一个字符串出现的字符,使其加一,而这里我们使用ASCI码分别来为字符串中出现的字母统计次数。然后再定义另外一个hash1
表,来统计其余字符串的字母出现情况,两表相互比对,最后再输出相同的hash
表中内容就行。
class Solution {
public:
vector<string> commonChars(vector<string>& A) {
vector<string> result;
if (A.size() == 0) return result;
int hash[26] = {0}; // 整合另外一个哈希表,作为输出结果
for (int i = 0; i < A[0].size(); i++) { // 标记第一个字符串的字母情况
hash[A[0][i] - 'a']++;
}
int hash1[26] = {0}; // 统计其余字符串外字符的出现频率
for (int i = 1; i < A.size(); i++) {
memset(hash1, 0, 26 * sizeof(int));
for (int j = 0; j < A[i].size(); j++) {
hashOtherStr[A[i][j] - 'a']++;
}
// 及时更新hash,以免影响后续的统计
for (int k = 0; k < 26; k++) {
hash[k] = min(hash[k], hash1[k]);
}
}
// 将hash统计的字符次数,转成输出形式
for (int i = 0; i < 26; i++) {
while (hash[i] != 0) { // 注意这里是while,多个重复的字符
string s(1, i + 'a'); // char -> string
result.push_back(s);
hash[i]--;
}
}
return result;
}
};
代码分析
这里我们用ASCII码来计算,利用字母减a
的哈希函数来建立我们的字母与hash
数组中出现的频率的关系。这里需要注意的是每次比对完一个字符串后,我们都需要及时更新hash
表中的内容,也就是这行hash[k] = min(hash[k], hash1[k]
,以免影响后续的统计。依次进行比对后,最后再把hash
表中值为一的地方,也就是共同字母,之后转换为字母输出。
总结
这次的题目还是比较简单的,情况也不是很复杂,初次试水哈希表,接触的也不是很难,后续还会讲解更难的题目,个人觉得我还要努力提升自我,代码之路还长,得慢慢走!
希望感兴趣的小伙伴一起学习,谢谢!