day05-数据结构力扣

哈希表理论基础

了解哈希表的内部实现原理,哈希函数,哈希碰撞,以及常见哈希表的区别,数组,set 和map。
什么时候想到用哈希法,当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法

什么是哈希表:

一个数组就是一张哈希表,,通过下标直接访问数组中的元素

例如要查询一个名字是否在这所学校里。

要枚举的话时间复杂度是O(n),但如果使用哈希表的话, 只需要O(1)就可以做到。

我们只需要初始化把这所学校里学生的名字都存在哈希表里,在查询的时候通过索引直接就可以知道这位同学在不在这所学校里了。

哈希函数

哈希函数,把学生的姓名直接映射为哈希表上的索引,然后就可以通过查询索引下标快速知道这位同学是否在这所学校里了。

哈希函数如下图所示,通过hashCode把名字转化为数值,一般hashcode是通过特定编码方式,可以将其他数据格式转化为不同的数值,这样就把学生名字映射为哈希表上的索引数字了。

如果学生数量大于哈希表大小,怎么办,哈希碰撞

哈希碰撞

两个学生都同时索引到一个下标,就是哈希碰撞

2种解决办法:拉链法,线性探测法

拉链法

线性探测法

例如冲突的位置,放了小李,那么就向下找一个空位放置小王的信息。所以要求tableSize一定要大于dataSize。

常见的3种哈希结构

常见的三种哈希结构核心作用都是快速判断元素是否在集合/快速做键值映射 ,用大白话解释如下:

  1. 数组:最基础的哈希结构,直接用数组下标 当作哈希表的"键",数组元素当作"值",通过下标一步找到对应内容,查询/增删都是O(1),缺点是下标只能是整数,且数组大小固定,容易浪费空间。

  2. set(集合):专门存不重复的单个元素 (部分变体如multiset可存重复),不用自己维护下标,直接存数据本身作为"键",能快速判断某个元素是否存在,适合只需要存值、不需要关联其他信息的场景。

  3. map(映射):存键值对(key-value),一个key对应一个value,通过key能快速找到对应的value,适合需要把两个相关数据关联起来的场景(比如存学生学号和对应姓名),key不能重复(multimap可重复),value无限制。

简单记:只存唯一值用set,存键值对应关系用map,下标能直接用、数据范围固定时用最基础的数组。

242.有效字母异位词

题目链接: 242. 有效的字母异位词 - 力扣(LeetCode)

判断两个字符串是不是由相同的字母但是可能不同顺序组成

没有用哈希,直接写,但是用了库函数

python 复制代码
class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        if sorted(s)==sorted(t):
            return True
        else:
            return False

思路

用一个26大小的哈希表存储,对应a-z,26个不同的字母。

先统计其中一个字符串每个字母出现的次数,放到对应的哈希表位置中。

在第二个字符串统计时,减去对应字母出现的次数

最后验证这个哈希表的所有值是不是为0,用于判断两个字符串的字母是否相同。

伪代码

python 复制代码
int hash[26];
for(i=0;i<s.size;i++):
    hash[s[i]-'a']++;//字母到下标的映射,把a对应到下标0的位置
for(i=0;i<t.size;i++):
    hash[s[i]-'a']--;
for(i=0;i<26;i++):
    if(hash[i]!=0):
        return false
return true
  

写题

python 复制代码
class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        hash=[0]*26
        i=0
        while(i<len(s)):
            hash[ord(s[i])-ord('a')]+=1
            i+=1
        i=0
        while(i<len(t)):
            hash[ord(t[i])-ord('a')]-=1
            i+=1
        i=0
        while(i<26):
            if hash[i]!=0:
                return False
            i+=1
        return True
  • 核心逻辑错误 :处理字符串 t 时,误将代码中的 t[i] 写成了 s[i]。这会导致程序用 s 的字符去抵消计数,而非 t 的字符。
  • 索引边界错误 :最初的代码中所有 while 循环条件用了 <=(如 i<=len(s)i<=26),而字符串 / 数组的索引范围是 0 ~ 长度-1,这会触发索引越界异常,导致程序直接崩溃。
  • 直接用si-'a'也会报错,在python里面

349. 两个数组的交集

题目链接349. 两个数组的交集 - 力扣(LeetCode)

python 复制代码
class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        res=[]
        i=0
        if len(nums1)<len(nums2):
            while(i<len(nums1)):
                if nums1[i] in nums2:
                    res.append(nums1[i])
                i+=1
        else:
            while(i<len(nums2)):
                if nums2[i] in nums1:
                    res.append(nums2[i])
                i+=1
        res=list(set(res))
        return res

思路

我还是想不到用哈希表,我刚开始就是像上面那样写的。

哈希表思路:

把nums1处理并放到哈希表里面,再去查nums2是否在哈希表里面出现过,如果出现过,我们就把结果放到result数组里面。

202. 快乐数

题目链接202. 快乐数 - 力扣(LeetCode)

python 复制代码
class Solution:
    def isHappy(self, n: int) -> bool:
        seen=[]
        while(n!=1):
            n=sum(int(i)**2 for i in str(n))
            if n in seen:
                return False
            seen.append(n)
        return True

1.两数之和

题目链接1. 两数之和 - 力扣(LeetCode)

python 复制代码
class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        res=[]
        i=0
        for i in range(len(nums)):
            if target-nums[i] in nums:
                res.append(i)
            elif nums[i]==target-nums[res[0]]:
                res.append(i)
        return res

刚开始看到自己写,

1.想要一个可以从数组值映射到数组下标的

2.单纯用if target-numsi in nums:判断是不行的,3,2,4和为6,会把下标0加入结果。

思路

map存放我们遍历过的元素,数组值作为键,下标作为值

2,7,3,6

找到2,想找7,查询是否遍历过7,没有遍历过,把2的键值对存入map

现在到7,想找2,查询是否遍历过7,遍历过,把map里面的2的下标放入结果。

伪代码

python 复制代码
unordered-map(int,int) map
for(i=0;i<nums.size;i++):
    s=target-nums[i];
    iter=map.find(s);
    if(iter!=map.end()):
        return iter->value,i
    map.insert(nums[i],i);

写题

1.给records定义错类型了,把dict弄成了list

2.index和vlaue的顺序

python 复制代码
        for index,value in enumerate(nums):
python 复制代码
class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        records=dict()
        for index,value in enumerate(nums):
            if target-value in records:
                return [records[target-value],index]
            records[value]=index
        return []
相关推荐
CSharp精选营5 天前
关系型 vs 非关系型:从原理到选型,一文搞定数据库核心分类
数据结构·nosql·关系型数据库·非关系型数据库·技术选型
To_OC6 天前
LC 207 课程表:刚学图论那会儿,我连这是拓扑排序都没看出来
javascript·算法·leetcode
To_OC6 天前
LC 208 实现 Trie 前缀树:曾被名字劝退,写完发现是送分题
javascript·算法·leetcode
To_OC7 天前
LC 994 腐烂的橘子:人人都说是 BFS 入门题,我却写了三遍才过
javascript·算法·leetcode
To_OC7 天前
LC 200 岛屿数量:经典 DFS 入门题,我第一次写居然连方向都搞错了
javascript·算法·leetcode
To_OC8 天前
LC 128 最长连续序列:别上来就排序,O (n) 解法才是这题的灵魂
javascript·算法·leetcode
刘马想放假8 天前
Modbus 全栈技术解析:TCP、RTU、ASCII、RTU over TCP
数据结构·网络协议
北域码匠9 天前
冒泡排序太慢?鸡尾酒排序双向优化,原生 C# 零第三方库完整代码
数据结构·排序算法·泛型·c# 算法·鸡尾酒排序·原生 c# 开发·冒泡排序优化·嵌入式算法
To_OC10 天前
LC 49 字母异位词分组:想到哈希表很简单,选对 key 才是精髓
javascript·算法·leetcode
To_OC11 天前
LC 1 两数之和:面试第一道必考题,暴力解法直接被面试官 pass
javascript·算法·leetcode