蓝桥杯基本知识——哈希表

一、概念

哈希表是基于键、值对存储的数据结构,底层一般采用的是列表(数组)。
大家都知道,基于列表(数组)的查询速度非常快,时间复杂度是O(1),常量级别的。
列表的底层存储结构是连续的内存区域,只要给定数据在列表(数组)中的位置,就能直接查询到数据。
哈希表适用于解决的问题:给你一个元素,判断在这个集合是否出现过。

二、 使用哈希表解决两类查找问题

查找有无:元素 ‘a’ 是否存在?可以使用 set 集合这种数据结构。
查找对应关系(键值对应):元素 ‘a’ 出现了几次?可以使用 dict 字典这种数据结构。

2.1集合set的使用

leetcode349.两个数组的交集
解题思路

  1. 先将数组1存储在哈希表中
  2. 数组2去遍历查询每一个数组在哈希表里是否出现过
  3. 如果出现过就把它放进result这个集合中
class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        a=set(nums1)
        b=set(nums2)
        c=a&b
        return list(c)

leecode202.快乐数
解题思路
可以用集合 set 来记录之前出现的数字。

  1. 第 1 部分我们按照题目的要求做数位分离,求平方和。
  2. 第 2 部分可以使用哈希集合完成。每次生成链中的下一个数字时,我们都会检查它是否已经在哈希集合中。
  3. 如果它不在哈希集合中,我们应该添加它。
  4. 如果它在哈希集合中,这意味着我们处于一个循环中,因此应该返回 false。
class Solution:
    def isHappy(self, n):
        ss = set()
        while True:
            if n == 1:
                return True
            total = 0
            while n:
                total += (n % 10) * (n %10)
                n = n // 10
            if total in ss:
                return False

            ss.add(total)
            n = total

leetcode217. 存在重复元素
解题思路

  1. 使用 set 集合存储前面遍历过的元素
  2. 对于每个元素 num[i],判断是否在前面的 recode 中,如果存在,返回 True。
class Solution:
    def containsDuplicate(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """

        n = len(nums)
        if n <= 1:
            return False

        recode = set()
        recode.add(nums[0])
        for i in range(1, n):
            if nums[i] in recode:
                return True
            recode.add(nums[i])
        return False

解题思路
用字典dict

  1. 对于每个元素都用哈希表去存储
  2. 如果遇到元素储存位置已经有元素,则说明遇到相同元素
class Solution:
    def containsDuplicate(self, nums: List[int]) -> bool:
        n = len(nums)
        if n == 1: return False
        dict = {}
        for num in nums:
            if num in dict:
                return True
            else: dict[num] = 1
        return False

2.2字典dict的使用

字典的格式:字典名 = {key1:value1, key2:value2,…}
定义一个空的字典:my_dict = {} 或 my_dict = dict()
1.两数之和
-enumerate()函数用于将一个可遍历的数据对象(如列表,元组或者字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。

// 哈希表
class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        hashtable = dict()
        for i, num in enumerate(nums):
            if target - num in hashtable:
                return [hashtable[target - num], i]
            hashtable[nums[i]] = i
        return []

常规解法–费时

class Solution(object):
    def twoSum(self, nums, target):
        for i in range(len(nums)):
            for j in range(i+1,len(nums)):
                if nums[i] + nums[j] == target:
                    return [i,j]

leetcode350.两个数组的交集II
解题思路
leetcode349.两个数组的交集相比,多加了记录元素个数的问题

  1. 由于同一个数字在两个数组中都可能出现多次,因此需要用哈希表存储每个数字出现的次数。对于一个数字,其在交集中出现的次数等于该数字在两个数组中出现次数的最小值。
  2. 首先遍历第一个数组,并在哈希表中记录第一个数组中的每个数字以及对应出现的次数
  3. 遍历第二个数组,对于第二个数组中的每个数字,如果在哈希表中存在这个数字,则将该数字添加到答案,并减少哈希表中该数字出现的次数。
    在这里插入图片描述
class Solution:
    def intersect(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: List[int]
        """
        m = len(nums1)
        n = len(nums2)
        if m == 0 or n == 0:
            return []

        dicts = {}
        for i in nums1:
            if i in dicts:
                dicts[i] += 1
            else:
                dicts[i] = 1

        ret = []
        for j in nums2:
            if j in dicts and dicts[j] > 0:
                ret.append(j)
                dicts[j] -= 1
        return ret

leetcode242.有效的字母异位词
解题思路

  1. 只要 t 中和 s 中字符都一样且数目都一样,那么就可以了。Python 实现的话可以采用 collections。Counter 这个函数实现对各个字符出现的次数进行统计。
  2. Counter 是 dict 字典的子类,Counter 拥有类似字典的 key 键和 value 值,只不过 Counter 中的键为待计数的元素,而 value 值为对应元素出现的次数 count。
class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        return Counter(s)==Counter(t)

leetcode205.同构字符串
解题思路

  1. 可以使用字典 dict 来记住这些字符对是一个很方便的做法。
  2. 用了两个字典 dict,一个字典 hashmap 用来记 s 的字符到 t 的映射,另一个字典 ismap 用来记录 t 的字符到 s 的映射
  3. 判断 t 中的两个字符不能由 s 中同一个字符映射而来。
class Solution:
    def isIsomorphic(self, s, t):
        hashmap = {}
        ismap = {}
        for i in range(len(s)):
            if s[i] in hashmap:
                if hashmap[s[i]] != t[i]:
                    return False
            else:
                if t[i] in ismap:
                    return False
                hashmap[s[i]] = t[i]
                ismap[t[i]] = True
        return True

leetcode387. 字符串中的第一个唯一字符
使用哈希表存储频数
我们可以对字符串进行两次遍历。在第一次遍历时,我们使用哈希映射统计出字符串中每个字符出现的次数。在第二次遍历时,我们只要遍历到了一个只出现一次的字符,那么就返回它的索引,否则在遍历结束后返回 −1。

class Solution:
    def firstUniqChar(self, s: str) -> int:
        frequency = collections.Counter(s)
        for i, ch in enumerate(s):
            if frequency[ch] == 1:
                return i
        return -1     

383. 赎金信
比较巧妙的就是使用collections.Counter() 统计字符串中各元素的数量,然后相减进行判断
collections.Counter(ransomNote) - collections.Counter(magazine)
在相减时,该函数默认使用被减数(减号前面的数是被减数,减号后面的数是减数)中含有的元素作为返回结果,对被减数不含有的元素进行忽略,返回结果是{key:value}
value = 被减数对应元素的value - 减数对应元素的value
当对应元素减数(magazine)value > 被减数(ransomNote)value时,返回空值;
最后使用not,not空值返回true, not num(num>0)返回false

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        frequency1=collections.Counter(ransomNote)
        frequency2 = collections.Counter(magazine) 
        if len(ransomNote) > len(magazine):
            return False
        return not frequency1 - frequency2

451. 根据字符出现频率排序
解题思路
通过一个字典 dict 存储所有字符出现的次数,因为某个字符的出现次数不可能超过 s 的长度,所以我们将每个字符根据其出现次数放入数组中的对应位置,那么最后我们只要从后往前遍历数组所有位置,将不为空的位置的字符串加入结果 ret 中即可。

from collections import Counter
class Solution:
    def frequencySort(self, s):
        n = len(s)
        sc = dict(Counter(s))
        ll = ['' for i in range(0, n+1)]
        isvisited = set()
        ret = ""
        for key,value in sc.items():
                ll[value] += key * value
        for i in range(n, -1, -1):
            if ll[i] != '':
                ret += ll[i]
        return ret;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值