代码随想录算法训练营Day6 | 哈希表理论基础、LeetCode242有效的字母异位词、LeetCode349两个数组的交集、LeetCode202快乐数、LeetCode1两数之和

哈希表理论基础

1、重要的事情放在开头,当看到需要在一个元素集合中查询是否存在某一个元素时,就应想到使用哈希法。

2、常见的哈希结构包括数组,set,map,数据本质上就是一个哈希表,哈希表就是利用关键码来访问数据,数组即是利用索引直接访问到数据值。

3、将不同数据类型的数据转换成关键码就用到了哈希函数,那么如果数据大小大于哈希表大小,导致存放数据间发生冲突,即哈希碰撞,应该怎么办呢,这时候考虑用拉链法,即在碰撞的位置存放一张链表来存放发生碰撞的数据;那如果可以保证数据大小是小于哈希表大小的,那可以使用线性探测法,当发生碰撞时,向下寻找下一个空位来存放发生碰撞的数据。

4、关于set(map)、multiset(map)、unordered_set(map)的特点如下表所示

当我们要使用集合来解决哈希问题的时候,优先使用unordered_set,因为它的查询和增删效率是最优的,如果需要集合是有序的,那么就用set,如果要求不仅有序还要有重复数据的话,那么就用multiset。

在map 是一个key value 的数据结构,map中,对key是有限制,对value没有限制的,因为key的存储方式使用红黑树(二叉平衡搜索树)实现的。map中虽然查询底层是红黑树,但对于我们还是hash来实现的,即通过关键值得方式来查找值。

综上所述,哈希法是用空间换取了时间,创建了一个额外的set或者map来存放数据

LeetCode242有效的字母异位词

该题目判断两个字符串是不是含有相同的字母(顺序可以不同),考虑到只包含a-z26个字符,数目较小,可以利用数组来实现哈希操作,维护一个长度为26得数组,利用ASCII码的减法获取数组下标,代码如下:

时间复杂度O(n);空间复杂度O(1);

class Solution {
public:
    bool isAnagram(string s, string t) {
        int hash[26]={0};
        int a=s.size();
        for(int i=0;i<s.size();i++) hash[s[i]-'a']++;
        
        for(int j=0;j<t.size();j++) hash[t[j]-'a']--;
        for(int k=0;k<sizeof(hash)/sizeof(hash[0]);k++){
            if(hash[k]!=0) return false;
        }
        return true;
    }
};

LeetCode349两个数组的交集

利用set:

注意:1、set的初始化可以直接通过vector转换;vector也可以直接通过set的迭代器转换;2、如果set未找到数值返回end();

时间复杂度(n+m) , m是要把set转换成vector;空间复杂度O(n)

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        // 利用set
        unordered_set<int> res_set;
        unordered_set<int> nums1_set(nums1.begin(),nums1.end());
        for(int num : nums2){
            if(nums1_set.find(num)!=nums1_set.end()){
                res_set.insert(num);
            }
        }
        return vector<int>(res_set.begin(),res_set.end());
    }
};

利用数组:
时间复杂度(n+m) , m是要把set转换成vector;空间复杂度O(n)

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        //利用数组
        int hash[1001]={0};
        unordered_set<int> res;
        for(int i=0;i<nums1.size();i++){
            hash[nums1[i]]=1;
        }
        for(int j=0;j<nums2.size();j++){
            if(hash[nums2[j]]==1){
                res.insert(nums2[j]);
            }
        }
        return vector<int>(res.begin(),res.end());
    }
};

LeetCode202快乐数

每次计算得到的结果存到哈希表中,如果计算结果等于1则返回true,如果计算结果已经存在于哈希表中,则返回false、

class Solution {
public:
    int get_num(int n){
        int sum=0;
        while(n){
            sum += (n%10)*(n%10);
            n = n/10;
        }
        return sum;
    }
    bool isHappy(int n) {
        unordered_set<int> res_set;
        while(get_num(n)!=1){
            if(res_set.find(get_num(n))!=res_set.end()) return false;
            res_set.insert(get_num(n));
            n = get_num(n);
        }
        return true;
    }
};

LeetCode1两数之和

根据数组值来判断是否两个数加和=target,返回下标。

本题需要注意的点在于:1、要想到用哈希法,当遍历数组元素的时候,需要判断target-元素值是不是曾经遍历过,因此想到用哈希法;
2、要返回下标索引,因此要想到用键值对的方式,数组值做键,下标做值(前提无重复元素)
3、pair<int,int>的用法,包括键值对的成员变量first,second要掌握。

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int,int> res_map;
        for(int i=0;i<nums.size();i++){
            if(res_map.find(target-nums[i])!=res_map.end()){
                return {res_map[target-nums[i]],i};
                // return {res_map.find(target-nums[i])->second,i};
            }
            res_map[nums[i]]=i;
            // res_map.insert(pair<int,int>(nums[i],i));
        }
        return {};
    }
};

  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值