LeetCode刷题小记 三、【哈希表】

1. 哈希表

文章目录

    • 1. 哈希表
    • 写在前面
      • 1.1 理论基础
      • 1.2 有效的字母异位词
      • 1.3 两个数组的交集
      • 1.4 快乐数
      • 1.5 两数之和
      • 1.6 四数相加||
      • 1.7 赎金信
      • 1.8 三数之和(哈希法梦碎的地方)
      • 1.9 四数之和
    • Reference

写在前面

本系列笔记主要作为笔者刷题的题解,所用的语言为Python3,若于您有助,不胜荣幸。

1.1 理论基础

哈希表[hash table]又称为散列表,它是一种通过键key与值value的映射关系来实现高效的增删查找操作,具体而言,我们是通过一个键key来对哈希表进行访问,查询获得其value。哈希表各种操作效率对比

数组链表哈希表
查找元素 O ( n ) \mathcal{O}(n) O(n) O ( n ) \mathcal{O}(n) O(n) O ( 1 ) \mathcal{O}(1) O(1)
添加元素 O ( 1 ) \mathcal{O}(1) O(1) O ( 1 ) \mathcal{O}(1) O(1) O ( 1 ) \mathcal{O}(1) O(1)
删除元素 O ( n ) \mathcal{O}(n) O(n) O ( n ) \mathcal{O}(n) O(n) O ( 1 ) \mathcal{O}(1) O(1)

在哈希表中进行增删查改的时间复杂度都是 O ( 1 ) \mathcal{O}(1) O(1) ,非常高效。

在哈希表中,我们将表中的每个空位称为桶[bucket],每个桶可以存储一个键值对,因此,查询操作就是找到key对应的桶,并在桶中获取value。在哈希表中如何对需要查询的元素进行定位呢?这里使用了一个函数来将key映射为哈希表中的位置,这个函数被称为hash()哈希函数,该函数的实现有许多中方式,这里不再展开。

如果哈希函数查询不同的key,但是出现了相同的返回值这应该怎么办呢?这种情况被称为哈希冲突,针对哈希冲突有多种扩容的方式,这里也不再展开。哈希表其实就是一种牺牲了空间来换取时间的数据结构。

当我们想使用哈希法来解决问题的时候,我们一般会选择如下的三种数据结构:

  • 数组
  • set(集合)
  • map(映射)/ dict(字典)

python3中内置的数据结构dict其实就是一种hash table

1.2 有效的字母异位词

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

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

解法一:数组

使用数组我们需要手搓一个hash函数

class Solution:def isAnagram(self, s: str, t: str) -> bool:hashtable: List = [0] * 26for char in s:hashtable[ord(char) - ord('a')] += 1for char in t:hashtable[ord(char) - ord('a')] -= 1for value in hashtable:if value != 0:return Falsereturn True

其中,python3内置函数ord()用于获取字符的 ASCII 码值或 Unicode 码值。将获取到字符的ASCII码与a的ASCII码相减,这样我们就获取到了在hashtable中存放的相对应索引,这就是我们手搓的hash函数。

解法二:使用字典

from collections import defaultdict
class Solution:def isAnagram(self, s: str, t: str) -> bool:hashs: dict = defaultdict(int)hasht: dict = defaultdict(int)for char in s:hashs[char] += 1for char in t:hasht[char] += 1return hashs == hasht 

这里需要注意defaultdict的用法,当defaultdict首次访问不存在的key时,会将其的值设置为0

1.3 两个数组的交集

349. 两个数组的交集

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

解法一:使用map

from collections import defaultdict
class Solution:def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:res: set = set()    # 用set来去重hashtable: dict = defaultdict(int)for n in nums1:hashtable[n] = 1for n in nums2:if hashtable[n] == 1:res.add(n)return list(res)

当我们需要考虑去重的时候,我们通常使用set数据结构来保存结果,set不允许有重复的元素存在,利用该特性自动完成去重。

class Solution:def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:res: set = set()hashtable: dict = {}for n in nums1:hashtable[n] = hashtable.get(n, 0) + 1for n in nums2:if hashtable.get(n, 0) != 0:res.add(n)return list(res)

自用内置的dict(),方法dict.get(key, defaultvalue),尝试查询key的值,如果key不存在则返回defaultvalue

解法二:使用数组

class Solution:def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:res: set = set()hashtable: List = [0]*1001	# 开辟存储空间for n in nums1:hashtable[n - 1] = 1for n in nums2:if hashtable[n - 1] == 1:res.add(n)return list(res)

解法三:python的特性

class Solution:def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:res: List = []for num in nums1:if num in nums2 and num not in res:res.append(num)return res
class Solution:def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:return list(set(nums1) & set(nums2))

1.4 快乐数

202. 快乐数

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

「快乐数」 定义为:

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

如果 n快乐数 就返回 true ;不是,则返回 false

这道题的关键在于无限循环上,如果我们按照常规思维来判断的话,我们不知道需要循环多少次,如果是无限循环的话,我们就无法跳出这个循环,那么应该如何解决呢?重点在于我们可以怎么判断它是否开始循环了,如果这个快乐数的演变过程中,出现了已经出现过的数,那么就表明它已经陷入循环了,那就肯定不是快乐数。所有这就是一个典型的查询过程,我们可以用哈希法来解决。

class Solution:def isHappy(self, n: int) -> bool:seen: set = {1}while n not in seen:	# 当n已经出现过则退出循环seen.add(n)n = sum([int(s)**2 for s in str(n)])return n == 1

1.5 两数之和

1. 两数之和

解法一:使用dict作为hash table

class Solution:def twoSum(self, nums: List[int], target: int) -> List[int]:record: dict = {}for index, value in enumerate(nums):res: int = target - valueif res in record:return [record[res], index]record[value] = index       # 保存新元素一定要放在后面,这样可以防止当前的value和record中的key冲突return []

解法二:使用set作为hash table

class Solution:def twoSum(self, nums: List[int], target: int) -> List[int]:record: set = set()     # 使用set作为hash tablefor index, value in enumerate(nums):res: int = target - valueif res in record:return [nums.index(res), index]record.add(value)return []

1.6 四数相加||

454. 四数相加 II

给你四个整数数组 nums1nums2nums3nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:

  • 0 <= i, j, k, l < n
  • nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0

我们将四个数组分别用A,B,C,D来表示,一个具体的思路是,我们先对其中2个数组进行遍历统计其和的出现次数(如a+b)生成一个hash table,然后再遍历剩余的两个数组来进行查找(c+d的负数在其中出现的次数),如果出现了a+b+c+d=0则符合要求,要求我们需要统计出现的次数,所以我们使用dict作为哈希表的结构。

为什么是分为两两来进行遍历呢?因为我们分为一个数组和三个数组来进行遍历的话,时间复杂度为 O ( n 3 ) \mathcal{O}(n^3) O(n3),两两遍历的时间复杂度为 O ( n 2 ) \mathcal{O}(n^2) O(n2),这样更优。

class Solution:def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:record: dict = {}count: int = 0for value1 in nums1:for value2 in nums2:record[value1 + value2] = record.get(value1 + value2, 0) + 1for value3 in nums3:for value4 in nums4:count += record.get(-(value3 + value4), 0)return count

1.7 赎金信

383. 赎金信

给你两个字符串:ransomNotemagazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。

如果可以,返回 true ;否则返回 false

解法一:使用dict

class Solution:def canConstruct(self, ransomNote: str, magazine: str) -> bool:record: dict = {}for char in magazine:record[char] = record.get(char, 0) + 1for char in ransomNote:if char not in record:return Falserecord[char] -= 1for times in record.values():if times < 0:return Falsereturn True

解法二:使用数组

class Solution:def canConstruct(self, ransomNote: str, magazine: str) -> bool:record: List = [0] * 26 # 因为字母一共26个for char in magazine:record[ord(char) - ord('a')] += 1for char in ransomNote:record[ord(char) - ord('a')] -= 1return all([value >= 0 for value in record])

1.8 三数之和(哈希法梦碎的地方)

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != kj != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

该题使用哈希法的话,去重的处理会非常复杂,所以使用双指针法比较方便,虽然相对简单了,但是还是涉及到一些去重的细节需要考虑清楚。

class Solution:def threeSum(self, nums: List[int]) -> List[List[int]]:nums.sort()     # 首先对nums进行排序result: List = []for index in range(len(nums)):if nums[index] > 0:     # 如果排序后的首元大于0,则说明不存在这样的组合return resultif index > 0 and nums[index] == nums[index - 1]:    # 对第一个元素进行去重continueleft: int = index + 1right: int = len(nums) - 1while left < right:if nums[index] + nums[left] + nums[right] > 0:right -= 1elif nums[index] + nums[left] + nums[right] < 0:left += 1else:result.append([nums[index], nums[left], nums[right]])while left < right and nums[left] == nums[left + 1]:    # 对剩余两个元素进行去重left += 1while left < right and nums[right] == nums[right - 1]:right -= 1left += 1right -= 1return result

1.9 四数之和

18. 四数之和

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

class Solution:def fourSum(self, nums: List[int], target: int) -> List[List[int]]:nums.sort()     # 排序result: List = []for i in range(len(nums)):if nums[i] > target and nums[i] > 0 and target > 0: # 剪枝breakif i > 0 and nums[i] == nums[i-1]:  # 去重continuefor j in range(i+1, len(nums)):if nums[i] + nums[j] > target and target > 0: # 剪枝breakif j > i+1 and nums[j] == nums[j-1]:    # 去重continue    left: int = j + 1right: int = len(nums) - 1while left < right:s: int = nums[i] + nums[j] + nums[left] + nums[right]if s < target:left += 1elif s > target:right -= 1else:result.append([nums[i], nums[j], nums[left], nums[right]])while left < right and nums[left] == nums[left+1]:left += 1while left < right and nums[right] == nums[right-1]:right -= 1left += 1right -= 1return result

Reference

[1] Hello 算法
[2] 代码随想录

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/699650.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WebServer -- 定时器处理非活动连接(下)

目录 &#x1f382;前言 &#x1f33c;定时器设计 &#x1f600;容器设计 &#x1f33c;任务处理函数 &#x1f6a9;源码分析&#xff08;定时器的使用&#xff09; &#x1f382;前言 PS&#xff1a;写博客 -- 巩固项目基础过程中&#xff0c;可以通过 GPT Google cpp…

基于事件触发机制的孤岛微电网二次电压与频率协同控制MATLAB仿真模型

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 本模型质量非常高&#xff0c;运行效果完美。本模型为4机并联孤岛系统&#xff0c;在下垂控制的基础上加入二次控制&#xff0c;二次电压与频率协同控制策略利用事件触发的方法来减少控制器的更新次数。该方法…

easyui 手风琴Accordion 面板的高度设置

今天接到一个新的小需求&#xff0c;如下图&#xff0c;当预算表单只有一个时&#xff0c;要求不显示预算表单这块的内容。 考虑到页面创建时用到了表单的回调和点击方法&#xff0c;所以不能单纯的移除&#xff0c;移除右侧表格的创建会报错&#xff0c;所以只能隐藏。 隐藏…

Docusaurus框架——快速搭建markdown文档站点介绍sora

文章目录 ⭐前言⭐初始化项目&#x1f496; 创建项目&#xff08;react-js&#xff09;&#x1f496; 运行项目&#x1f496; 目录文件&#x1f496; 创建一个jsx页面&#x1f496; 创建一个md文档&#x1f496; 创建一个介绍sora的文档 ⭐总结⭐结束 ⭐前言 大家好&#xff0…

劫持已经存在的DLL

这里找到一个成功加载的 这里先把原来程序正常的dll改名为libEGL1.dll&#xff0c;然后将我们自己的dll改名为libEGL.dll 然后再重新执行程序&#xff0c;这里同样是弹出了窗口

QEMU源码全解析 —— virtio(20)

接前一篇文章&#xff1a; 上回书重点解析了virtio_pci_modern_probe函数。再来回顾一下其中相关的数据结构&#xff1a; struct virtio_pci_device struct virtio_pci_device的定义在Linux内核源码/drivers/virtio/virtio_pci_common.h中&#xff0c;如下&#xff1a; /* O…

centos7 docker 安装

1.卸载之前docker环境 sudo yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docke…

Sora-OpenAI 的 Text-to-Video 模型:制作逼真的 60s 视频片段

OpenAI 推出的人工智能功能曾经只存在于科幻小说中。 2022年&#xff0c;Openai 发布了 ChatGPT&#xff0c;展示了先进的语言模型如何实现自然对话。 随后&#xff0c;DALL-E 问世&#xff0c;它利用文字提示生成令人惊叹的合成图像。 现在&#xff0c;他们又推出了 Text-t…

编程笔记 Golang基础 023 切片

编程笔记 Golang基础 023 切片 一、切片二、定义与初始化三、基本操作四、示例 Go语言中的切片&#xff08;slices&#xff09;是基于数组的抽象数据类型&#xff0c;它提供了一种灵活的方式来处理可变长度的数据序列。切片本身不存储任何数据&#xff0c;而是指向底层数组的一…

bat脚本进程停止与启动

在Windows操作系统中&#xff0c;批处理&#xff08;Batch&#xff09;脚本是一种常见的自动化脚本工具&#xff0c;通过BAT文件来执行一系列DOS命令。通过BAT脚本&#xff0c;我们可以轻松地控制进程的启动和停止。 一、进程停止 在BAT脚本中&#xff0c;要停止一个进程&…

如何设计一个数模混合芯片?

一、如何设计一个数模混合芯片&#xff1f; 根据需求功能设计数模混合芯片的架构是一个多步骤的过程。以下是一些关键步骤和考虑因素&#xff1a; 需求分析&#xff1a;首先&#xff0c;需要明确数模混合芯片的功能需求。这包括确定模拟电路和数字电路的具体需求&#xff0c;以…

推荐几个不错的技术管理的视频讲座

推荐几个不错的技术管理的视频讲座&#xff0c;均来自DEEPLUS公众号组织的线上视频讲座&#xff0c;地址如下&#xff1a; 1&#xff09; 技术管理者如何搭班子、带队伍&#xff1f;技术管理者如何搭班子、带队伍&#xff1f;_哔哩哔哩_bilibili 2&#xff09; 从技术转管理后&…

Stable Diffusion 3 发布,AI生图效果,再次到达全新里程碑!

AI生图效果&#xff0c;再次到达全新里程碑&#xff01; Prompt&#xff1a;Epic anime artwork of a wizard atop a mountain at night casting a cosmic spell into the dark sky that says "Stable Diffusion 3" made out of colorful energy 提示&#xff08;意译…

靡语IT:JavaScript函数

目录 一、基本概念 二、函数的声明和调用&#xff1a; 1、创建函数&#xff1a; ​编辑 2 、函数调用&#xff1a; 3、函数参数&#xff1a; 三、全局变量和局部变量 1、局部JavaScript 变量 2 、全局 JavaScript 变量 四、arguments 对象: 五、return 作用 六、嵌…

172基于matlab的MPPT智能算法

基于matlab的MPPT智能算法&#xff0c;通过细菌觅食进行优化。算法引入了趋向性操作&#xff0c;用以进行局部范围内的最优寻找&#xff1b;引入了复制操作&#xff0c;用以避免种群更新盲目随机性&#xff0c;加快了算法的收敛速度&#xff1b;引入了迁徙操作用以避免算法陷入…

【深度学习笔记】卷积神经网络——填充和步幅

填充和步幅 在前面的例子 fig_correlation中&#xff0c;输入的高度和宽度都为 3 3 3&#xff0c;卷积核的高度和宽度都为 2 2 2&#xff0c;生成的输出表征的维数为 2 2 2\times2 22。 正如我们在 sec_conv_layer中所概括的那样&#xff0c;假设输入形状为 n h n w n_h\tim…

【Flink精讲】Flink组件通信

主要指三个进程中的通讯 CliFrontendYarnJobClusterEntrypointTaskExecutorRunner Flink内部节点之间的通讯使用Akka&#xff0c;比如JobManager和TaskManager之间。而operator之间的数据传输是利用Netty。 RPC是统称&#xff0c;Akka&#xff0c;Netty是实现 Akka与Ac…

Window系统上通过SSH搭建git服务器

Window系统上通过SSH搭建git服务器 1. OpenSSH安装&#xff08;如果已安装&#xff0c;请忽略&#xff09; 打开“设置”&#xff0c;选择“系统”&#xff0c;然后选择“可选功能”。 扫描列表&#xff0c;查看是否已安装 OpenSSH。 如果未安装&#xff0c;请在页面顶部选择…

Java实现毕业生追踪系统 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 登陆注册模块2.2 学生基本配置模块2.3 就业状况模块2.4 学历深造模块2.5 信息汇总分析模块2.6 校友论坛模块 三、系统设计3.1 用例设计3.2 实体设计 四、系统展示五、核心代码5.1 查询我的就业状况5.2 初始化就业状况5.…

[算法沉淀记录] 排序算法 —— 希尔排序

排序算法 —— 希尔排序 算法介绍 希尔排序&#xff08;Shell Sort&#xff09;是一种基于插入排序的算法&#xff0c;由Donald Shell于1959年提出。希尔排序的基本思想是将待排序的序列划分成若干个子序列&#xff0c;分别进行插入排序&#xff0c;待整个序列中的记录基本有…