LeetCode第三章哈希表|242.有效的字母异位词,349. 两个数组的交集,202. 快乐数,1. 两数之和

哈希表理论基础

1.哈希表

哈希表即为散列表。

哈希表是根据关键码的值而直接进行访问的数据结构。

什么时候使用哈希表呢?当需要快速判断一个元素是否出现集合里时。

2.哈希函数

查询信息与哈希表索引的映射关系则需要哈希函数来确定。

例如,把学生的姓名直接映射为哈希表上的索引。

通过特定的编码方式,把学生名字转化为数值,映射为哈希表的索引,这样就可以通过查询索引下标来快速确认该学生是否存在。

哈希表2

3.常见的三种哈希结构

  1. 数组

    数组本身就是一种简单的哈希表。当数值比较小且数值可控时,可以使用数组作为哈希表,通过数组下标来直接访问数组中的元素。

  2. set(集合)

    数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。

    这时候就可以使用set作为哈希表,可以大大减少内存空间的浪费。

  3. map(映射)

    map 是一个key value 的数据结构。当同时需要索引和数值信息时,即使用map作为哈希表。

242_有效的字母异位词

题目链接:242. 有效的字母异位词

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。

示例 1:

输入: s = "anagram", t = "nagaram"
输出: true

示例 2:

输入: s = "rat", t = "car"
输出: false

解法:用数组实现HashMap

  1. 解法

    首先比较容易想到的就是暴力解法,两层for循环来记录重复字符出现的次数。

    优化一下可以使用哈希表。

    上面有提到数组就是一种简单的哈希表。本题数值较小且范围可控,所以可以使用数组来实现哈希表。

    因为a~z为26个小写字母,因此定义一个大小为26的record数组,初始化为0,用来存放每个字母的出现次数。

    遍历s字符串,将s[i] - 'a'所在的元素进行 +1 操作,证明s[i]字符出现了一次;再遍历t字符串,将s[i] - 'a'所在的元素进行 -1 操作。最后再遍历一遍record数组,如果数组中存在不为0的元素,则 s 和 t 不互为字母异位词。

    在这里插入图片描述

    在这里插入图片描述

  2. 代码展示

    bool isAnagram(string s, string t) {
        int record[26] = { 0 };
        for (int i = 0; i < s.size(); i++) {
            record[s[i] - 'a']++;
        }
        for (int i = 0; i < t.size(); i++) {
            record[t[i] - 'a']--;
        }
        for (int i = 0; i < 26; i++) {
            if (record[i] != 0) {
                return false;
            }
        }
        return true;
    }
    
    
  3. 复杂度分析:

    • 时间复杂度:O(n)
    • 空间复杂度:O(1)

相关题目:

  • 383.赎金信
  • 49.字母异位词分组
  • 438.找到字符串中所有字母异位词

349_两个数组的交集

题目链接:349. 两个数组的交集

给定两个数组 nums1nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序

示例 1:

输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]

示例 2:

输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4]
解释:[4,9] 也是可通过的

解法一:用set实现HashMap

  1. 解法

在这里插入图片描述

nums1和nums2为题中所给数组。

  • 定义两个set哈希表,分别是nums1_set和result,nums1_set用来存放nums1中的元素,result用来存放最终交集结果。
  • 将nums1中元素存入nums1_set,记录了nums1中的元素,顺便完成了去重操作。
  • 遍历nums2,找到与nums1_set中相同的元素,存入result。
  1. 代码实现

    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int> nums1_set(nums1.begin(), nums1.end());
        unordered_set<int> res_set;
        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());
    }
    
  2. 复杂度分析

    • 时间复杂度:O(n)
    • 空间复杂度:O(n)

解法二:用数组实现HashMap

  1. 解法

    因为本题LeetCode上给了限制

    • 1 <= nums1.length, nums2.length <= 1000
    • 0 <= nums1[i], nums2[i] <= 1000

    这样就属于较小且可控的数值范围,所以也可以用数组来实现哈希表。

    • 定义一个比1000稍大一点的数组作为哈希表,数组索引表示数值,对应值为1即为出现过;为0即为没出现过。
    • 遍历nums1,把出现过的数组索引对应的值置为1
    • 定义一个res_set,使用set,因为最终要去重
    • 遍历nums2,如果对应哈希表中的值为1,则将索引值插入res_set
  2. 代码实现

    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int> res_set;
        int hash[1005] = { 0 }; 
        for (int num : nums1) { 
            hash[num] = 1;
        }
        for (int num : nums2) { 
            if (hash[num] == 1) {
                res_set.insert(num);
            }
        }
        return vector<int>(res_set.begin(), res_set.end());
    }
    
  3. 复杂度分析

    • 时间复杂度:O(n)
    • 空间复杂度:O(n)

相关题目:

  • 350.两个数组的交集 II

202_快乐数

题目链接:202. 快乐数

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

示例 1:

输入:n = 19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1

示例 2:

输入:n = 2
输出:false

解法一:用set实现HashMap

  1. 解法

    存在两种可能:

    • 最终值为1

      在这里插入图片描述

    • 最终进入循环

    在这里插入图片描述

    所以本题的关键就在于判断是否存在循环。

    • 首先定义一个哈希表set,用来存放每一轮的sum值。
    • 每次对当前的sum值进行判断,如果sum值为1,则是快乐数;如果不为1且不在set中,则继续计算;如果不为1且存在于set中,证明已经发生循环,不是快乐数。
  2. 代码展示

    int getSum(int n) {	// 求各位数平方和
        int sum = 0;
        while (n)
        {
            sum += (n % 10) * (n % 10);
            n = n / 10;
        }
        return sum;
    }
    
    bool isHappy(int n) {
        unordered_set<int> sum_set;
        while (1)
        {
            int sum = getSum(n);
            if (sum == 1) {
                return true;
            }
            if (sum_set.find(sum) != sum_set.end()) {
                return false;
            }
            else {
                sum_set.insert(sum);
            }
            n = sum;
        }
    
    }
    
  3. 复杂度分析

    • 时间复杂度:O(logn)
    • 空间复杂度:O(logn)

1_两数之和

题目链接:1. 两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1]

示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]

示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]

解法:用map实现HashMap

  1. 解法

    • 为什么用哈希表?

在这里插入图片描述

  • 为什么用map

    对于本题来说,我们不仅要能确认数组对应的值,也要能返回数组下标,因此需要使用map,即key-value结构存放。

    key——数组元素

    value——数组下标

  • 解题过程

在这里插入图片描述

在这里插入图片描述

  1. 代码展示
vector<int> twoSum(vector<int>& nums, int target) {
    unordered_map<int, int> res_map;	// 定义哈希表
    for (int i = 0; i < nums.size(); i++) {
        auto iter = res_map.find(target - nums[i]);	// 查找对应元素是否出现过
        if (iter != res_map.end()) {	// 出现过,则返回{查找元素下标, 当前元素下标}
            return { iter->second, i };	
        }
        res_map.insert(pair<int, int>(nums[i], i));		// 没出现过,则把(下标,数值)插入到哈希表中
    }
    return {};
}
  1. 复杂度分析

    • 时间复杂度:O(n)
    • 空间复杂度:O(n)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值