LeetCode题解 哈希表(一):理论基础、242 有效的字母异位词、349 两个数组的交集、350 两个数组的交集II

哈希表

理论基础 ——

哈希表更属于一种思想,即快速判断一个元素是不是在表里,本质上属于使用空间换时间,基于这种思想,衍生出了用法与特殊的容器

这种思想可以抽象为一个函数,通过把key值编码成hashcode,就可以用hashcode表示key值;如果待存入的key值大于表的大小,那么可以通过取表大小模的方式,就可使所有元素在表中都有映射 。

这就导致了哈希碰撞问题的出现:如果两个不同元素,映射到了同一位置,应该怎么办?

解决方法一般而言有两种,拉链法和线性探测法

拉链法的思想很简单,就是把表定义为一个一个的链表,如果映射到同一位置,直接存储在next地址里,就像个拉链一样,一直往下顺;

另一种方法是线性探测法,此时需要保证标的大小,大于数据的大小,依靠表中必然会出现的空位置来解决碰撞问题

在我的印象里,哈希表还有很多可以深挖的细节,此处可以放到研究STL的时候,详细了解。

常用的哈希结构——

注:表格参考代码随想录

  • 数组

    用数组表示,value就是index,数组类型可以有所不同

  • set(集合

    集合又分为以下三种

    集合底层实现是否有序数值是否可以重复能否更改数值查询效率增删效率
    std::set红黑树有序O(logn)O(logn)
    std::multiset红黑树有序O(logn)O(logn)
    std::unordered_set哈希表无序O(1)O(1)
  • map(映射

    map也可以分为以下三种

    映射底层实现是否有序数值是否可以重复能否更改数值查询效率增删效率
    std::map红黑树有序O(logn)O(logn)
    std::multimap红黑树有序O(logn)O(logn)
    std::unordered_map哈希表无序O(1)O(1)
242 有效的字母异位词 easy

有两个字符串,判断组成这两个字符串的字母和数量是不是都一样

方法是,先建立一个unordered_map,遍历其中一个字符串,记录各字符出现的次数

然后再遍历第二个字符串,清除各字符出现的次数,再遍历第三次,如果某字符串出现的次数小于0,就返回false

由于是字母,所以用hash数组表示也可以

bool isAnagram(string s, string t) {
    int hash [26] = {};
    for (char c: s) {
        hash[c - 'a']++;
    }
    for (char c: t) {
        hash[c - 'a']--;
    }
    for (int i = 0; i < 26; i++) {
        if (hash[i] != 0) 
            return false;
    }

    return true;
}
349 两个数组的交集 easy

先把一个数组遍历一遍,把出现过的数字放在unordered_set中,

然后再遍历第二个数组,找数字是不是在哈表集合中出现,如果出现了,就记录一下结果,记录结果也要使用一个set,因为放置重复的元素出现

vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
    unordered_set<int> res;
    unordered_set<int> intersection(nums1.begin(), nums1.end());

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

    return vector<int>(res.begin(), res.end());
}
350 两个数组的交集II easy

与上一题不同,这次要统计的结果中每个元素出现的次数,应当与该元素在两个数组中都出现的次数一致,出现次数不一致,那么就返回较小值

方法就是用一个哈希map,记录每个数字出现的次数,遍历第二个数组的时候,减去数字出现的次数,如果这个数出现的次数等于0,那么在map中删除该数字就可以了

vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
    if (nums1.size() > nums2.size()) {
        return intersect(nums2, nums1);
    }
    unordered_map <int, int> m;
    for (int num : nums1) {
        ++m[num];
    }
    vector<int> intersection;
    for (int num : nums2) {
        if (m.count(num)) {
            intersection.push_back(num);
            --m[num];
            if (m[num] == 0) {
                m.erase(num);
            }
        }
    }
    return intersection;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值