结合 LeetCode 谈谈哈希表在算法问题上的应用
从
LeetCode
前一百道题中总结了些哈希表(unordered_map
)应用于算法问题的场景,在恰当的时候使用哈希表可以大幅提升算法效率,比如:统计字符串中每个字符或单词出现的次数、从一维数组中选择出两个数使之与某数相等。
在开始之前,首先简要的介绍一下哈希表(又称散列表),心急的同学可以跳转到LeetCode部分。
哈希表介绍
哈希表查找的时间复杂度最差是O(n),平均时间复杂度O(1),因此,理想状态哈希表的使用和数组很像。
散列表使用某种算法操作(散列函数)将键转化为数组的索引来访问数组中的数据,这样可以通过Key-value
的方式来访问数据,达到常数级别的存取效率。现在的nosql
数据库都是采用key-value
的方式来访问存储数据。
散列表是算法在时间和空间上做出权衡的经典例子。通过一个散列函数,将键值key映射到记录的访问地址,达到快速查找的目的。如果没有内存限制,我们可以直接将键作为数组的索引,所有的操作操作只需要一次访问内存就可以完成。
散列函数
散列函数就是将键转化为数组索引的过程,这个函数应该易于计算且能够均与分布所有的键。
散列函数最常用的方法是除留余数法
,通常被除数选用素数
,这样才能保证键值的均匀散布。
散列函数和键的类型有关,每种数据类型都需要相应的散列函数;比如键的类型是整数,那我们可以直接使用除留余数法
;键的类型是字符串的时候我们任然可以使用除留余数法
,可以将字符串当做一个特别大的整数。
int hash = 0;
for (int i=0;i<s.length();i++){
hash = (R*hash +s.charAt(i)%M);
}
或者
Hash hashCode(char *key){
int offset = 5;
Hash hashCode = 0;
while(*key){
hashCode = (hashCode << offset) + *key++;
}
return hashCode;
}
使用时 hashCode(key) & (size-1)
就可以得到一个 size-1
范围内的hash值