算法学习day6
1. 哈希表理论基础
1.哈希表基础.
哈希表是根据关键码的值直接访问的数据结构。
例:数组,数组下标(关键码)。通过下标直接访问数组中的元素。
一般哈希表都是用来快速判断一个元素是否出现在集合里。
2.哈希函数.
例:哈希函数,可以将学生的姓名直接映射为哈希表上的索引,通过查询索引下标可以知道同学是否在这所学校里。
3.哈希碰撞.
图片来源:代码随想录
2. 力扣242题-有效的字母异位词
2.1 分析
1.数组是一个简单的哈希表,题目中字符串不含有大写。定义一个大小为26的数组来统计。
2.首先将26个字母映射成数字当做数组的下标来统计数量。s[i] - ‘a’,a-z用下标索引0-25表示。同时将索引对应的元素的值加1.
3.同理统计第二字符串并将索引对应的元素减1.
4.最后循环遍历数组,如果存在有不为0的数值。说明字符串s、t,不相同(指的是内容不同)、位置无关。否则说明为有效的字母异位词。
2.2 代码
class Solution {
public:
bool isAnagram(string s, string t) {
int num[26] = {0};
//将26个字母映射成数字当做数组的下标统计数量
for(int i = 0 ; i < s.size() ; i++){
num[s[i]-'a']++;
}
//统计第二个字符串,并减1
for(int i = 0 ; i < t.size() ; i++){
num[t[i]-'a']--;
}
//若为有效的字母异位词数组必全为零,若出现其他值,必为false
for(int i = 0 ; i < 26 ; i++){
if(num[i] !=0){
return false;
}
}
return true;
}
};
3. 力扣349题-两个数组的交集
3.1 分析
1.std::set、std::multiset底层实现是红黑树。std::unordered_set底层实现是哈希表。使用unordered_set读写效率最高,且不需要对数据进行排序。
2.定义一个result的set哈希表,存放最后要返回的结果,因为unordered_set可以在插入元素的时候自动去重。
3.将nums1中的元素放入另外一个unordered_set nums_set中,去重。
4.遍历nums2中的元素,若发现元素在nums_set中也存在,将该元素插入到result中。
5.遍历结束将result转换回vector.
3.2 代码
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> result;
unordered_set<int> nums_set(nums1.begin(),nums1.end());
for(int i = 0 ; i < nums2.size() ; i++){
//如果nums2[i]元素不存在集合nums_set中,返回迭代器nums_set.end()
if(nums_set.find(nums2[i]) != nums_set.end()){
//不用考虑去重操作了
result.insert(nums2[i]);
}
}
return vector<int>(result.begin(),result.end());
}
};
4. 力扣202题-快乐数
4.1 分析
1.关键点:当重复出现就不是快乐数了。
4.2 代码
class Solution {
public:
//求各个位置上数字的平方和
int getSum(int n){
int sum = 0;
while(n){
sum += (n%10) * (n%10);//算每一位的平方和
n = n /10;//移动数字的位
}
return sum;
}
bool isHappy(int n) {
//快速判断一个元素是否出现在集合里,用哈希法
//当sum重复说明不是快乐数
unordered_set<int> set;
while(1){
int sum = getSum(n);
//如果上来直接就找到了
if(sum == 1){
return true;
}
//如果这个sum重复出现,陷入死循环,说明不是快乐数
if( set.find(sum) != set.end()){
return false;
}else{
set.insert(sum);
}
n = sum;//更新,用新数值,继续求平方和,检测是否快乐数
}
}
};
5. 力扣1题-两数之和
5.1 分析
1.当我们需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,就要第一时间想到哈希法。
2.key来存放元素,value来存放下标,使用map刚刚好.
3.遍历nums数组,目标值减去当前遍历到的数组。剩余的数在map中找(利用相减可以找到满足目标值的两个数字)。若找到:直接返回,没有找到往map里面存。
图片来源:代码随想录
5.2 代码
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> map;
for(int i = 0 ; i < nums.size() ; i++){
//在map中找,目标值-元素 含有。若存在返回
//map 中键(key)存放元素 值(valur)存放下标
if(map.find(target - nums[i]) != map.end()){
return {map.find(target - nums[i])->second,i};
}
//在map中找,目标值-元素 不含有。插入map中
else{
map.insert(pair<int,int>(nums[i],i));
}
}
//没找到返回空
return {};
}
};