一.哈希表
概念
哈希表是一个利用哈希函数来储存数据,储存位置的数据结构,通常支持一下操作:
- insert(key,value): 插入键值对(key,value)
- get(key): 如果存在键入的key值对则返回其值value,否则返回空值
- delete(key): 删除键为key的键值对
哈希表(Hash Table,又称散列表),是一种线性表的存储结构。哈希表由一个直接寻址表和一个哈希函数构组成。哈希函数h(k)将元素关键字k作为自变量,返回元素存储的下标。如图所示
哈希冲突
哈希冲突:由于哈希表的大小是有限的,而要存储的总量是无限的,因此对于任何哈希函数,都会出现两个不同元素映射到同一个位置上的情况,这种情况叫做哈希冲突。比如h(k)=k%7,h(0)=h(7)=h(14)
解决哈希冲突方法:
1.开放寻址法:如果哈希函数返回位置已经有值,则可以向探查新的位置来存储这个值。
线性探索:如果位置i被占用,则探查i+1,i+2,……
二次探索:如果位置i被占用,则探查 i + 1 2 , i − 1 2 , i + 2 2 , i − 2 2 … … i+1^2,i-1^2,i+2^2,i-2^2…… i+12,i−12,i+22,i−22……,
二度哈希:有n个哈希函数,当使用第一个哈希函数h1发生冲突时。则尝试下一个函数。
2.拉链法
哈希函数
除法哈希法:h(k)=k%m
乘法哈希法: h ( k ) = f l o o r ( m ∗ ( A ∗ k e y ) ) h(k)=floor(m*(A*key)) h(k)=floor(m∗(A∗key))
全域哈希法: h a , b ( k ) = ( ( a ∗ k e y + b ) m o d p ) m o d m h_{a,b}(k)=((a*key+b)mod\enspace p)mod\enspace m ha,b(k)=((a∗key+b)modp)modm
a,b=1,2,3……p-1, mod=%
二.哈希结构-集合
c++标准库提供了三种集合的数据结构,分别如下
集合 | 底层实现 | 是否有序 | 数值是否可以重复 | 能否更改数值 | 查询效率 | 增删效率 |
---|---|---|---|---|---|---|
std::set | 红黑树 | 有序 | 否 | 否 | O(log n) | O(log n) |
std::multiset | 红黑树 | 有序 | 是 | 否 | O(logn) | O(logn) |
std::unordered_set | 哈希表 | 无序 | 否 | 否 | O(1) | O(1) |
当我们要使用集合来解决哈希问题的时候,优先使用unordered_set,因为它的查询和增删效率是最优的,如果需要集合是有序的,那么就用set,如果要求不仅有序还要有重复数据的话,那么就用multiset。
三.题目描述
「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
如果 n 是快乐数就返回 True ;不是,则返回 False 。
示例:
输入:19
输出:true
解释:
1^2 + 9^2 = 82
8^2 + 2^2 = 68
6^2 + 8^2 = 100
1^2 + 0^2 + 0^2 = 1
四.思路
可以设置循环来不断更新输入值,当输入值变为1则循环结束,输出true。当循环过程中两次出现同一个值,说明进入了死循环,判断同一个值是否出现两次可以借助unordered_set储存每次的输入值,当输入值可以在集合中找到时则视为其出现两次.
五.代码
class Solution {
public:
bool isHappy(int n) {
unordered_set<int> set;//定义集合保存每次的求和值
while(1){
int sum=0;
while(n)//求每位的平方和
{
int spe=n%10;
n/=10;
sum+=(spe*spe);
}
if(sum==1)//快乐数
return true;
if (set.find(sum) != set.end())//在集合中出现过,陷入循环
return false;
else
set.insert(sum);// 添加到集合中
n=sum;
}
}
};
set.end()返回指向容器中最后一个元素之后位置的迭代器,set.find(key)表示查找值为key的元素,如果找到,则返回一个指向该元素的正向迭代器;如果没找到,则返回一个与end()方法相同的迭代器。set.find(sum) != set.end()则表示查询值在集合中。