Leetcode-哈希表篇 Day6

141 阅读6分钟

代码随想录算法训练营第六天| 242.有效的字母异位词、349.两个数组的交集、202.快乐数、1.两数之和

这里简单介绍一下哈希表的基础知识。

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

哈希表能解决什么问题呢,一般哈希表都是用来快速判断一个元素是否出现集合里。

常见的三种哈希结构:

  • 数组——哈希值比较小,范围也比较小
  • set(集合)——数值很大
  • map(映射)——key对应value

总结一下,当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法
但是哈希法也是牺牲了空间换取了时间,因为我们要使用额外的数组,set或者是map来存放数据,才能实现快速的查找
如果在做面试题目的时候遇到需要判断一个元素是否出现过的场景也应该第一时间想到哈希法!

  • 242.有效的字母异位词

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

思路:本题利用数组作为哈希表,数组大小为26。定义一个数组叫做record用来上记录字符串s里字符出现的次数,需要把字符映射到数组也就是哈希表的索引下标上,因为字符a到字符z的ASCII是26个连续的数值,所以字符a映射为下标0,相应的字符z映射为下标25

在遍历字符串s的时候,只需要将 s[i] - ‘a’ 所在的元素做+1操作即可,检查字符串t中是否出现了这些字符,在遍历字符串t的时候,对t中出现的字符映射哈希表索引上的数值再做-1的操作。

最后检查一下,record数组如果有的元素不为零0,说明字符串s和t一定是谁多了字符或者谁少了字符,return false。如果record数组所有元素都为零0,说明字符串s和t是字母异位词,return true。

Python:

class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        record = [0] * 26
        for i in range(len(s)):
            #并不需要记住字符a的ASCII,只要求出一个相对数值就可以了
            record[ord(s[i]) - ord("a")] += 1
        print(record)
        for i in range(len(t)):
            record[ord(t[i]) - ord("a")] -= 1
        for i in range(26):
            if record[i] != 0:
                #record数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。
                return False
        return True
  • 349.两个数组的交集

题目链接 题意:给定两个数组,编写一个函数来计算它们的交集。

图片.png

注意题目特意说明:输出结果中的每个元素一定是唯一的,也就是说输出的结果的去重的, 同时可以不考虑输出结果的顺序。但是要注意,使用数组来做哈希的题目,是因为题目都限制了数值的大小

而这道题目没有限制数值的大小,就无法使用数组来做哈希表了。而且如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费。此时就要使用另一种结构体了,setset.

Python3:

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        return list(set(nums1) & set(nums2))    # 两个数组先变成集合,求交集后还原为数组
  • 202.快乐数

力扣题目链接 编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数

思路:题目中说了会 无限循环,那么也就是说求和的过程中,sum会重复出现,这对解题很重要!

Python:

class Solution:
    def isHappy(self, n: int) -> bool:
        def calculate_happy(num):
            sum_ = 0
            
            # 从个位开始依次取,平方求和
            while num:
                sum_ += (num % 10) ** 2
                num = num // 10
            return sum_

        # 记录中间结果
        record = set()

        while True:
            n = calculate_happy(n)
            if n == 1:
                return True
            
            # 如果中间结果重复出现,说明陷入死循环了,该数不是快乐数
            if n in record:
                return False
            else:
                record.add(n)
  • 1.两数之和

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

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

思路:暴力解法是两层for循环,时间复杂度为O(n2)O(n^2)。强调一下 什么时候使用哈希法,当我们需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,就要第一时间想到哈希法。

本题呢,就需要一个集合来存放我们遍历过的元素,然后在遍历数组的时候去询问这个集合,某元素是否遍历过,也就是 是否出现在这个集合。因为我们不仅要知道元素有没有遍历过,还有知道这个元素对应的下标,需要使用 key value结构来存放,key来存元素,value来存下标,那么使用map正合适

使用数组和set来做哈希法的局限。

  • 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
  • set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,不仅要判断y是否存在而且还要记录y的下标位置,因为要返回x 和 y的下标。所以set 也不能用。

map是一种key value的存储结构,可以用key保存数值,用value在保存数值所在的下标。

map目的用来存放我们访问过的元素,所以 map中的存储结构为 {key:数据元素,value:数组元素对应的下表}。在遍历数组的时候,只需要向map去查询是否有和目前遍历元素比配的数值,如果有,就找到的匹配对,如果没有,就把目前遍历的元素放进map中,因为map存放的就是我们访问过的元素。

图片.png

图片.png

总结:本题其实有四个重点:

  • 为什么会想到用哈希表
  • 哈希表为什么用map
  • 本题map是用来存什么的
  • map中的key和value用来存什么的