代码随想录Day6 | 哈希表理论基础 242.有效的字母异位词349. 两个数组的交集 202. 快乐数1. 两数之和

本文详细介绍了哈希表的基础概念,包括哈希函数、哈希碰撞的解决方法以及不同哈希结构的应用。此外,还涵盖了有效字母异位词、两个数组的交集、快乐数和两数之和等LeetCode题目,展示了如何利用哈希表优化算法解决问题。
摘要由CSDN通过智能技术生成

代码随想录Day6 | 哈希表理论基础 242.有效的字母异位词349. 两个数组的交集 202. 快乐数1. 两数之和

哈希表基础

哈希表是根据关键码的值而直接进行访问的数据结构
其作用:判断一个元素是否出现在集合里

哈希函数和哈希碰撞

将一段数据映射到哈希表上的处理方法,但对于一个数组来说,其长度是有限的,如果数据元素个数大于其长度,会产生不同数据出现在统一索引位置这就是哈希碰撞。
哈希碰撞的解决方法:拉链法和线性检测法

  1. 拉链法:将冲突的元素存储在链表中,链表的起点就是被冲突的索引地址
  2. 线性探测法:哈希表的容量大于数据个数,利用冲突位置的下一个空位置来存放冲突元素。

三种哈希结构

  1. 数组
    对于映射长度可控的可以使用,比如英文字母
  2. set集合
    代码随想录
    代码随想录
  3. map映射
    代码随想录
    在这里插入图片描述
  4. 使用场景
    优先使用unordered_set,利用其较好的查找删除效率,如果要求集合是有序的那么可以利用set,如果集合中需要存在重复数据那么就利用multiset

有效的字母异位词

文档讲解:代码随想录
视频讲解: 学透哈希表,数组使用有技巧!Leetcode:242.有效的字母异位词
状态:×

  1. 思路
    由于对于小写字母来说,只有26个,所以可以利用数组来充当哈希表,那么如何构造哈希函数–将字母变为数字下标,利用字母的ASCII码值即可,char-‘a’。
    遍历s的时候对下标对应的值进行+1操作,在遍历t的时候对下标对应的值进行-1操作。
    最后的检测就是数组中的数据是否全为0。
class Solution {
public:
    bool isAnagram(string s, string t) {
        vector<int> check(26,0);
        for(int i = 0;i<s.length();i++)
        {
            check[s[i]-'a']++;
        }
        for(int i = 0;i<t.length();i++)
        {
            check[t[i]-'a']--;
        }
        for(int i = 0;i<26;i++)
        {
            if(check[i] != 0)
            {
                return false;
            }
        }
        return true;
    }
};

时间复杂度: O ( 3 n ) O(3n) O(3n)

两个数组的交集

文档讲解:代码随想录
视频讲解: 学透哈希表,set使用有技巧!Leetcode:349. 两个数组的交集
状态:可以用数组,不会set

  1. 数组思路
    与上一题类似,因为元素的个数最多是1001个,所以可以考虑使用数组。那么就i需要自己构建哈希函数,我们将元素值作为哈希表的索引值即可。
    但这道题还需要考虑一些情况,因为这道题是需要找出相同的数,并且不重复的输出。
    那么上一道题利用等于一个val的判断就不适用了,因为初始化哈希数组,会将所有元素变为这个val。第二点是不重复,如果我们在第一数组进行映射的时候还是将索引对应的值++,那么最后判断的时候会出现重复,或者避免了重复会出现结果为空,比如nums2中只有1个值,而nums1中有多个。
    所以做法是,每次映射值的时候将索引对应的值变为1,然后找到值进行–操作,这样当哈希数组中的值变为0的时候,那说明存在相交,且这个值只会被加入一次,因为之后再存在就是负数了。
    对于避免加入本来就不存在数的情况,将返回数组的更新放在检查第二个数组的循环里面进行。
    具体代码如下
class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        vector<int> res;
        vector<int> check(1001);

        for(int i = 0;i<nums1.size();i++)
        {
            check[nums1[i]] = 1;
        }
        for(int i = 0;i<nums2.size();i++)
        {
            check[nums2[i]]--;
            if(check[nums2[i]] == 0)
            {
                res.push_back(nums2[i]);
            }
        }
        return res;
    }
};
  1. 哈希表思路
    对于不重复且不排序就考虑使用unordered_set<>
//定义哈希表
unordered_set<TYPE> Name;
//定义同时赋值
unordered_set<TYPE> Name(list1.begin(),list1.end());
//查找元素是否出现
Name.find(num) != Name.end() //当num对应的位置不是最后一个说明存在
//插入元素
Name.insert(num);

本题的具体代码

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int> res;//用于去重
        unordered_set<int> check(nums1.begin(),nums1.end());//用于存储检测

        for(int num:nums2)
        {
            if(check.find(num) != check.end())
            {
                res.insert(num);
            }
        }

        return vector<int>(res.begin(),res.end());
    }
};

快乐数

文档讲解:代码随想录
视频讲解:
状态:×

  1. 思路
    无限循环说明会有重复的结果出现,可以考虑使用哈希表,n比较大所以使用数组不再合适,使用unordered_set当之后出现的数在set里面发现,那么就可以返回false并终止循环。
    本题代码如下
class Solution {
public:
    bool isHappy(int n) {
        //无限循环说明会有重复
        unordered_set<int> check;
        
        while(1)
        {
            //每次开始循环之前初始化平方和结果
            int final = 0;

            //计算平方和结果
            while(n)
            {
                
                final += (n%10)*(n%10);
                n = n/10;
            }
            //将平方和结果变为下一次循环的n
            n = final;
            
            //当平方和结果为1 返回true跳出循环
            if(final == 1)
            {
                return true;
                break;
            }
            
            //当平方和结果之前存在,返回false跳出循环
            if(check.find(final) != check.end())
            {
                return false;
                break;
            }
            //当平方和结果不为1,且不存在添加到set中
            else
            {
                check.insert(final);
            }
        }
    }
};

时间复杂度: O ( l o g n ∗ 1 ) O(logn * 1) O(logn1) logn是求平方和的时间

两数之和

文档讲解:代码随想录
视频讲解: 梦开始的地方,Leetcode:1.两数之和,学透哈希表,map使用有技巧!
状态:只会暴力

  1. 思路
    不重复出现,说明我们需要利用unordered来存放满足条件的值。
    返回下标,不是返回值,说明我们需要存放一个类似字典的数据(val,index)
    所以考虑使用map
//返回一个数组
return {a,b};

//map的一些操作
//定义
unordered_map<int,int> check;
//定义查找的变量利用auto pair<int,int>
auto i= check.find(target);
//pair<int,int>第一个数据存放的是我们的target,第二个数据存放的是我们的下标,map去find的时候,是去搜寻第一个值,所以第一个值应当为我们的target
//获取方式
i->first;
i->second;
//插入一组数据,与查询相对应
check.insert(pair<int,int>(nums[i),i);

本题代码如下

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int,int> check;
        for(int i = 0;i<nums.size();i++)
        {
            int mubiao = target-nums[i];
            if(check.find(mubiao) != check.end())
            {
                return {i,check.find(mubiao)->second};
            }
            else
            {
                check.insert(pair<int, int>(nums[i], i));
            }
        }
        return {};
    }
};
  • 18
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值