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,这会触发索引越界异常,导致程序直接崩溃。
  • 直接用s[i]-'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-nums[i] 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 []
相关推荐
im_AMBER9 分钟前
Leetcode 145 回文数 | 加一
数据结构·算法·leetcode
HLC++10 分钟前
数据结构--树
c语言·开发语言·数据结构
楼田莉子20 分钟前
C++数据结构:基数树
开发语言·数据结构·c++·学习
Tisfy24 分钟前
LeetCode 2906.构造乘积矩阵:前后缀分解
算法·leetcode·前缀和·矩阵·题解·前后缀分解
weixin_6495556743 分钟前
C语言程序结构第四版(何钦铭、颜晖)第十章函数与程序结构之递归实现顺序输出整数
c语言·数据结构·算法
旖-旎1 小时前
前缀和(和为K的子数组)(5)
c++·算法·leetcode·前缀和·哈希算法·散列表
进击的荆棘1 小时前
优选算法——链表
数据结构·算法·链表·stl
凌波粒1 小时前
LeetCode--203.移除链表元素(链表)
java·算法·leetcode·链表
Q741_1471 小时前
力扣经典模板题 前缀积 力扣 2906. 构造乘积矩阵 每日一题 哈希表 找规律 力扣 13. 罗马数字转整数 C++
算法·leetcode·前缀和·矩阵
lcj25111 小时前
蓝桥杯C++:数据结构
数据结构·c++·算法