目录
哈希表理论基础
242.有效的字母异位词
349. 两个数组的交集
202. 快乐数
1. 两数之和
前言:需要掌握——哈希表的内部实现原理、哈希函数、哈希碰撞、常见哈希表的区别、数组、set和map
什么时候想到用哈希表:当我们遇到了要快速判断一个元素是否出现在集合里的时候,就要考虑哈希法
1、定义:哈此表是根据关键码的值而直接进行访问的数据结构
例如:数组就是一张哈希表,哈希表中的关键码就是数组的索引下标,通过下标直接访问数组中的元素
2、什么时候用哈希表:快速判断一个元素是否出现在集合里
例如:查询一个名字是否在这所学校里。要枚举的话时间复杂度是O(n),但如果使用哈希表的话,只需要O(1)就可以做到。我们只需要初始化把这所学校里学生的名字都存在哈希表里,在查询的时候通过索引直接就可以知道这位同学在不在这所学校里了。
将学生姓名映射到哈希表上就涉及到了hash function,也就是哈希函数。
3、哈希函数:将数据映射到哈希表上的映射关系
4、常见的三种哈希结构:数组、set(集合)、map(映射)
key的范围小、可控就用数组,大一点就用set,如果有key和value就用map
set和map分别提供以下三种数据结构,底层实现及优劣如下表所示:
①set:
set和multiset底层:红黑树,红黑树是一种平衡二叉搜索树,所以key值是有序的,但key不可以修改,改动key会导致整棵树的错乱,所以只能删除和增加key
unordered_set底层:哈希表
当我们需要使用集合来解决哈希函数的问题:
1)优先使用unordered_set,因为它的查询和增删效率是最优的,
2)如果需要集合是有序的,那么就用set
3)如果要求集合有序且有重复数据,就用multiset
②map:map是一个key value数据结构
map和multimap底层:红黑树,同上key值也是有序的,key也不可以修改,对value没有限制
unordered_map底层:哈希表
5、哈希法:
使用这些数据结构来解决映射问题的方法,我们称之为哈希法
6、小结:
1、当遇到判断一个元素是否出现在某集合中时,要想到用哈希法
2、哈希法是用空间换时间,因为要使用额外的数组,set或是map来存放数据,才能实现快速查找
3、如果在做面试题目的时候遇到需要判断一个元素是否出现过的场景也应该第一时间想到哈希法
力扣:给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。如“abbc”和“bbac”就是异位词
1、小写字母的ASCII码是连续的,key范围小,用数组
2、关键:用字符相减(ASCII码)构建hash表
3、代码:
class Solution {
public:
bool isAnagram(string s, string t) {
//哈希法
int hash[26] = {0};
//用s构建hash表
for(int i=0 ; i
力扣:给定两个数组,编写一个函数来计算它们的交集。[1,2,2,1]和[2,2]交集为[2]
1、unorderede_set自动去重,(multiset里的元素可以重复)
2、C++11中的foreach
#include
using namespace std;
int mian()
{
int nums[10] = {1};
for(int num: nums)
{
cout << num << endl; //输出10个1
}
system("pause");
return 0;
}
3、把数组里的数赋值给set和set赋值给vector是一样的
4、定义了两个unordered_set,一个用于查找,一个利用set去重的性质
5、代码:
class Solution {
public:
vector intersection(vector& nums1, vector& nums2) {
unordered_set nums_set(nums1.begin(), nums1.end());
unordered_set result;
for(int num: nums2)
{
if(nums_set.find(num) != nums_set.end()) result.insert(num);
}
vector result_final(result.begin(),result.end());
return result_final;
}
};
力扣:编写一个算法来判断一个数 n 是不是快乐数。「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。如果 n 是快乐数就返回 True ;不是,则返回 False 。
1、得到数字各个位单数
while(n != 0)
{
cout << n % 10 << endl; //此处为得到每个位置上的数
n /= 10;
}
2、代码:
class Solution {
public:
int getSum(int n){
int sum = 0;
while(n!=0)
{
sum += (n%10)*(n%10);
n /= 10;
}
return sum;
}
bool isHappy(int n) {
//定义哈希set
unordered_set nums_set;
int sum = 0;
while(1)
{
sum = getSum(n);
n = sum;
if(sum == 1) return true;
if(nums_set.find(sum) != nums_set.end()) return false;
nums_set.insert(sum);
}
}
};
力扣:给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
1、unordered_map的一些基本操作:
//定义nums_map
unordered_map nums_map;
//插入元素,插入nums数组的值和对应标号
nums_map.insert(pair(nums[i],i));
//查找是否等于target的key值
auto iter = nums_map.find(target); //注意find是查找key
if(iter!=nums_map.end()) return iter->second; //找到了返回这个key的value
2、代码:
class Solution {
public:
vector twoSum(vector& nums, int target) {
//哈希表
unordered_map nums_map;
for(int i=0;isecond, i};
nums_map.insert(pair(nums[i],i));
}
return {};
}
};