【算法专场】哈希表
目录
前言
哈希表
1. 两数之和 - 力扣(LeetCode)
算法分析
算法代码
面试题 01.02. 判定是否互为字符重排
编辑算法分析
算法代码
217. 存在重复元素
算法分析
算法代码
219. 存在重复元素 II
算法分析
算法代码
解法二
算法代码
算法分析
算法代码
49. 字母异位词分组
算法分析
算法代码
前言
当我们想要快速查找某个值是否存在,或者想要对数据进行去重的时候,我们有没有方法可以解决上面这些问题?我们可以用哈希表。
哈希表
哈希表(Hash Table)是一种通过哈希函数将键(key)映射到表中位置来访问记录的数据结构,它具有高效的数据查找、插入和删除能力。
我们什么时候可以使用哈希表?
在快速查找、频繁统计、快速映射、去重的情景下都可以使用哈希表。
我们来通过算法题目来更好的了解哈希算法。
1. 两数之和 - 力扣(LeetCode)
算法分析
本道题要求我们从数组中找两个数,并且两数之和为target。这道题可以采用暴力枚举,时间复杂度为O(n^2),如果在大量数据的情况下,是会超时的,那么我们可以采用哈希算法来解决这道题。
我们可以在hash表中存储元素以及其下标的映射。在遍历数组的过程,每次判断(target-当前元素)是否在hash表中存在,如果不存在,那就将
当前元素以及其下标存到hash表中,反之,如果找到,那么就取出下标返回。
为什么不将所有元素都放进去hash表再进行判断?这样的话就无法解决元素重复的问题。假设目标值为2,那么现在有1,我们如果将1先放进了hash表,那么我们在遍历的时候,可以找到1,但实际上这两个1是同一个。而如果我们先判断hash表中是否存在(target-当前元素)的元素,则可以避免出现重复的情况。
算法代码
/*** 解决方案:找出数组中两个数之和等于目标值的数对索引* 方法:使用哈希表实现* 时间复杂度:O(n),其中n是数组的长度* 空间复杂度:O(n),需要额外的空间来存储哈希表* * @param nums 输入的整数数组* @param target 目标值,寻找两数之和等于此值* @return 返回一个长度为2的整数数组,包含满足条件的两个数的索引;如果不存在这样的数对,则返回{-1, -1}*/
public int[] twoSum(int[] nums, int target) {// 利用哈希表来存储已经遍历过的数字及其索引,以便快速检查目标值与当前值的差值是否已经出现过HashMap<Integer,Integer> map=new HashMap<>();for(int i=0;i<nums.length;i++){// 检查当前数字与目标值的差值是否已经在哈希表中if(map.containsKey(target-nums[i])){// 如果差值存在,则找到了满足条件的两个数,返回它们的索引return new int[]{map.get(target-nums[i]),i};}else{// 如果差值不存在,将当前数字及其索引放入哈希表中,以供后续查找使用map.put(nums[i],i);}}// 如果遍历完整个数组后仍未找到满足条件的数对,返回{-1, -1}return new int[]{-1,-1};
}
时间复杂度为O(n),空间复杂度为O(n).
面试题 01.02. 判定是否互为字符重排
算法分析
本道题其实就是要判断两个字符串是否是一样,那么我们就可以两个hash表,来存储每次字符出现的次数,如果两个hash表对应的值都相等,那就说明两个字符串是一样的。
算法代码
/*** 检查两个字符串是否互为字符重排* * @param s1 第一个字符串* @param s2 第二个字符串* @return 如果两个字符串互为字符重排,则返回true;否则返回false*/public boolean CheckPermutation(String s1, String s2) {// 如果两个字符串长度不同,则它们不可能互为字符重排if (s1.length() != s2.length()) {return false;}// 如果任一字符串为空,则它们不可能互为字符重排if (s1.length() == 0 || s2.length() == 0) {return false;}// 创建一个哈希表来存储字符出现的次数,ASCII码共有128个字符,额外留一个位置给可能的空字符int hash[] = new int[129];// 遍历第一个字符串,统计每个字符出现的次数for (int i = 0; i < s1.length(); i++) {char ch = s1.charAt(i);hash[ch]++;}// 遍历第二个字符串,检查每个字符是否在哈希表中出现过,并减少相应字符的计数for (int i = 0; i < s2.length(); i++) {char ch = s2.charAt(i);// 如果字符在哈希表中的计数为0,则说明两个字符串的字符组成不同if (hash[ch] == 0) {return false;}hash[ch]--;}// 如果所有字符都能一一对应,且没有多余的字符,则两个字符串互为字符重排return true;}
217. 存在重复元素
算法分析
这道题就是要求在数组中有没有一个元素是出现超过两次的,我们可以用哈希算法来解决这道题,利用HashSet,如果set里面没有存在当前元素,就将当前元素存到set中;反之,如果有,则返回true。
算法代码
public boolean containsDuplicate(int[] nums) {HashSet<Integer> hashSet=new HashSet<>();for(int i=0;i<nums.length;i++){if(hashSet.contains(nums[i])){return true;}hashSet.add(nums[i]);}return false;}
219. 存在重复元素 II
算法分析
跟上一道题类似,不过这里还需要将下标进行存储,需要利用HashMap,在遍历的过程中,如果当前元素在hashmap中已经存在,那么就判断这两个元素之间的距离,如果小于k,则返回true,否则将当前元素以及其下标存储到hashmap中。
算法代码
/*** 检查数组中是否存在两个相同的数字,且它们的索引之差的绝对值最大为k* 这个方法通过使用HashMap来跟踪数字及其最后出现的索引来实现* 如果发现重复数字,并且它们的索引之差不超过k,则返回true* 如果不满足这些条件,则在遍历完整个数组后返回false* * @param nums 输入的整数数组* @param k 索引之差的绝对值的最大允许值* @return 如果找到至少一对索引之差的绝对值不超过k的相同数字,则返回true;否则返回false*/public boolean containsNearbyDuplicate2(int[] nums, int k) {// 使用HashMap来存储数字及其对应的索引HashMap<Integer, Integer> map = new HashMap<>();for(int i=0;i<nums.length;i++){// 检查当前数字是否已经在HashMap中存在if(map.containsKey(nums[i])){// 如果当前数字已存在,并且当前索引与之前索引之差不超过k,则返回trueif(i-map.get(nums[i])<=k){return true;}}// 更新或添加当前数字及其索引到HashMap中map.put(nums[i],i);}// 如果没有找到满足条件的数字对,则返回falsereturn false;}
时间复杂度为O(n),空间复杂度为O(n)
解法二
对于这道题,我们还可以通过滑动窗口的思想来解决,题目要求在数组中找两个相同的元素,并且他们下标的距离要小于等于k,那么我们就可以通过维护一个长度为k的窗口。如果当窗口小于k的时候,那么我们就将元素添加到窗口中,如果窗口中存在和当前元素相同的元素,那么就直接返回true,反之,则将元素添加到窗口中,当元素的个数等于窗口的长度的时候,那就将左边第一个元素进行移除。这里我们借助HashSet来判断窗口中是否有重复的元素。
算法代码
/*** 检查数组中是否存在重复的元素,且它们的索引之差的绝对值最大为k* 这个方法用于识别在一定索引范围内是否存在重复的数字** @param nums 一个整数数组,其中可能包含重复元素* @param k 索引之差的绝对值的最大允许值* @return 如果找到至少一对索引之差的绝对值不超过k的重复元素,则返回true;否则返回false*/public boolean containsNearbyDuplicate(int[] nums, int k) {// 使用HashSet存储当前窗口内的元素,以便快速检查重复Set<Integer> set = new HashSet<>();for (int i = 0; i < nums.length; i++) {// 当窗口大小超过k时,移除窗口最左侧的元素,以保持窗口大小不超过kif (i > k) {set.remove(nums[i - k - 1]);}// 尝试将当前元素添加到HashSet中如果添加失败,说明存在重复元素,且索引之差不超过kif (!set.add(nums[i])) {return true;}}// 遍历完成后,如果没有返回true,说明没有找到满足条件的重复元素return false;}
算法分析
这道题相对于前面两道题来说,要难上一些。但是以及依旧可以借鉴上面题目的思想,利用滑动窗口+有序集合。
根据题意,假设任意位置为i,值为u。我们希望在下标范围为[max(0,i-k),i)的范围内找到值范围在[u-t,u+t]范围内的数。如果我们每次遍历到任意位置的时候,都往前检查k个元素,这样时间负责度会达到O(nk),会超时,所以我们需要对检索后面k个元素进行优化,在java中,有一个TreeSet数据结构,能够帮助我们在有序集合内快速找到值小于等于u或者大于等于u的值。
算法代码
/*** 检查数组中是否存在两个索引之差不超过indexDiff且值之差不超过valueDiff的元素* * @param nums 包含整数的数组* @param indexDiff 索引之间的最大差值* @param valueDiff 值之间的最大差值* @return 如果找到满足条件的元素对,则返回true;否则返回false*/public boolean containsNearbyAlmostDuplicate(int[] nums, int indexDiff, int valueDiff) {int n = nums.length;TreeSet<Integer> set = new TreeSet<>();for(int i=0;i<n;i++){int u=nums[i];//如果set不为空,从set中找到大于等于u的最小值(最接近u的数)Integer ceil = set.ceiling(u);//如果set不为空,且小于等于u的最大值(最接近u的数)Integer floor = set.floor(u);//检查是否存在满足条件的元素if(ceil!=null&&ceil-u<=valueDiff) return true;if(floor!=null&&u-floor<=valueDiff) return true;//将当前元素加入setset.add(u);//如果当前索引大于等于indexDiff,则从set中移除滑动窗口最左侧的元素if(i>=indexDiff) set.remove(nums[i-indexDiff]);}//遍历后仍未找到满足条件的元素,返回falsereturn false;}
49. 字母异位词分组
算法分析
这道题要我们找字符串的字符个数都相同的字符串,并将这些字符串都放在同一个列表中,那么我们可以采用哈希算法,这里借助HashMap,键key为字符串,值为一个存储着字符串的列表。在遍历字符串数组的时候,我们每次将字符串进行排序,再判断hashmap是否存储当前字符串,如果存在,则将当前元素添加到列表中,反之,则创建一个列表,并将当前元素添加到列表中。最后再将map中的值存储放到ans中。
算法代码
/*** 对字符串数组进行遍历,将其中的字符串转换为字符数组并排序,然后转换回字符串* 使用HashMap来存储这些转换后的字符串作为键,以及它们在原始数组中的出现情况作为值* 最后,将HashMap中的所有值收集到一个二维列表中并返回* * @param strs 字符串数组,包含待处理的字符串* @return 返回一个二维列表,其中包含按照字母异位词分组的字符串列表*/
public List<List<String>> groupAnagrams(String[] strs) {// 初始化答案列表List<List<String>> ans=new ArrayList<>();// 初始化哈希图,用于存储排序后的字符串作为键,以及它们的出现情况作为值HashMap<String,List<String>> map=new HashMap<>();// 遍历输入的字符串数组for(int i=0;i<strs.length;i++){// 获取当前遍历到的字符串String s=strs[i];// 将字符串转换为字符数组char[] chars=s.toCharArray();// 对字符数组进行排序Arrays.sort(chars);// 将排序后的字符数组转换回字符串s=new String(chars);// 如果排序后的字符串已经在哈希图中存在if(map.containsKey(s)){// 将当前字符串添加到该键对应的列表中map.get(s).add(strs[i]);}else{// 否则,创建一个新的字符串列表List<String> list=new ArrayList<>();// 将当前字符串添加到列表中list.add(strs[i]);// 将排序后的字符串和对应的字符串列表作为键值对存入哈希图map.put(s,list);}}// 遍历哈希图的所有键for(String key:map.keySet()){// 将每个键对应的值(字符串列表)添加到答案列表中ans.add(map.get(key));}// 返回答案列表return ans;
}
以上就是哈希算法篇的所有内容啦~
若有不足,欢迎指正~
相关文章:

【算法专场】哈希表
目录 前言 哈希表 1. 两数之和 - 力扣(LeetCode) 算法分析 算法代码 面试题 01.02. 判定是否互为字符重排 编辑算法分析 算法代码 217. 存在重复元素 算法分析 算法代码 219. 存在重复元素 II 算法分析 算法代码 解法二 算法代码 算法…...

Beszel监控Docker安装
一、Beszel Hub安装 #Beszel Hub安装 mkdir -p ./beszel_data && \ docker run -d \--name beszel \--restartunless-stopped \-v ./beszel_data:/beszel_data \-p 8090:8090 \henrygd/beszel#创建账号 账号/密码:adminadmin.com/adminadmin.com 二、Besz…...
如何学习Elasticsearch(ES):从入门到精通的完整指南
如何学习Elasticsearch(ES):从入门到精通的完整指南 嘿,小伙伴们!如果你对大数据搜索和分析感兴趣,并且想要掌握Elasticsearch这一强大的分布式搜索引擎,那么你来对地方了!本文将为…...
【mybatis】基本操作:详解Spring通过注解和XML的方式来操作mybatis
mybatis 的常用配置 配置数据库连接 #驱动类名称 spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driver #数据库连接的url spring.datasource.urljdbc:mysql://127.0.0.1:3306/mybatis_test characterEncodingutf8&useSSLfalse #连接数据库的名 spring.datasourc…...

CSV格式和普通EXCEL格式文件的区别
CSV 文件(.csv) 普通的 Excel 文件(.xlsx 或 .xls) 主要体现在 文件格式、数据存储、功能支持 等方面: 文件格式 比较项CSV 文件 (.csv)Excel 文件 (.xlsx/.xls)文件类型纯文本文件二进制或 XML 格式数据分隔逗号(,)…...

使用 Vite + React 19 集成 Tailwind CSS 与 shadcn/ui 组件库完整指南
使用 Vite React 19 集成 Tailwind CSS 与 shadcn/ui 组件库完整指南 🌟 前言一、创建 React 19 项目二、集成 Tailwind CSS1️⃣ 安装依赖2️⃣ 配置 Vite 插件3️⃣ 引入 Tailwind4️⃣ 启动项目 三、配置路径别名1️⃣ 修改 TypeScript 配置2️⃣ 安装类型声明3…...
【java】基本数据类型和引用数据类型
在 Java 中,数据类型分为 基本数据类型 和 引用数据类型。它们的本质区别在于存储方式和操作方式。下面我会详细解释这两种数据类型,并用通俗易懂的语言帮助你理解。 1. 基本数据类型(Primitive Data Types) 基本数据类型是 Java…...

mybatis-lombok工具包介绍
Lombok是一个实用的]ava类库,能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,并可以自动化生成日志变量,简化java开发、提高效率。 使用前要加入Lombok依赖...

2. grafana插件安装并接入zabbix
一、在线安装 如果不指定安装位置,则默认安装位置为/var/lib/grafana/plugins 插件安装完成之后需要重启grafana 命令在上一篇讲到过 //查看相关帮助 [rootlocalhost ~]# grafana-cli plugins --help //从列举中的插件过滤zabbix插件 [rootlocalhost ~]# grafana…...

零基础学CocosCreator·第九季-网络游戏同步策略与ESC架构
课程里的版本好像是1.9,目前使用版本为3.8.3 开始~ 目录 状态同步帧同步帧同步客户端帧同步服务端ECS框架概念ECS的解释ECS的特点EntityComponentSystemWorld ECS实现逻辑帧&渲染帧 ECS框架使用帧同步&ECS 状态同步 一般游戏的同步策略有两种:…...
为什么配置Redis时候要序列化配置呢
序列化和反序列化?: 序列化:将对象转换为二进制数据,以便存储到Redis中。 反序列化:将Redis中的二进制数据转换回对象,以便在应用程序中使用。 1. 默认序列化器的问题 如果不配置序列化器,Re…...
使用爬虫获取1688商品分类:实战案例指南
在电商领域,获取商品分类信息对于市场分析、选品决策和竞争情报收集至关重要。1688作为国内领先的B2B电商平台,提供了丰富的商品分类数据。通过爬虫技术,我们可以高效地获取这些分类信息,为商业决策提供有力支持。 一、为什么选择…...

C#打印设计器
C# 打印设计器,功能强大却操作简单,小白也能快速上手! 主要功能: 支持多种设计元素: 文字、图片、图形、二维码、条形码等,满足您多样化的设计需求。 灵活排版,精准定位: 支持拖拽…...
Codeforces Round 1004 (Div. 2)(A-E)
题目链接:Dashboard - Codeforces Round 1004 (Div. 2) - Codeforces A. Adjacent Digit Sums 思路 只有两种情况:n1之后没有进位,y-x1。n1之后进位(y-x-1)%90。 代码 void solve(){int x,y;cin>>x>>y;if(y-x1){cout<<…...

pnpm的使用
pnpm的使用 1.安装和使用2.统一包管理工具下载依赖 1.安装和使用 pnpm:performant npm ,意味“高性能的npm”。 pnpm由npm/yarn衍生而来,解决了npm/yarn内部潜在的bug,极大的优化了性能,扩展了使用场景。被誉为“最先进的包管理工具”。 pnpm安装指令: npm i -g p…...

vscode调试redis
系统:ubuntu redis:redis-6.0.3 1.在vs中安装c/c编译插件 2.用vscode打开redis-6.0.3 3.在菜单中找到run->Add Configuration… 4.会在目录中生成一个./vscode目录,里面包含launch.json,修改launch.json中的program:${workspaceFolder}…...
Windows逆向工程入门之汇编指令格式与操作数类型
公开视频 -> 链接点击跳转公开课程博客首页 -> 链接点击跳转博客主页 目录 一、汇编指令格式基础 二、操作数类型详解 1. 立即数(Immediate) 2. 寄存器操作数(Register) 3. 内存操作数(Memory&#…...
亚远景-ASPICE 4.0与敏捷开发:如何实现高效协同
ASPICE 4.0与敏捷开发的结合是汽车软件开发领域的重要趋势。通过合理融合,可以实现高效协同,提升软件开发的质量和效率。以下是实现高效协同的关键要点: 1. 理解ASPICE 4.0与敏捷开发的互补性 ASPICE 4.0强调软件开发过程的规范性、可追溯性…...

pptx文档提取信息
目录 一、前言二、python-pptx提取核心代码三、LibreOffice 转换pdf再提取的核心代码一、前言 pptx文档提取解析常用的库。 如果只需要解析 .pptx 的文本、表格、图片,推荐使用 python-pptx(开源,轻量级)。 如果需要高性能、支持 .ppt、动画、格式转换,推荐 Aspose.Slid…...
蓝桥杯篇---超声波距离测量频率测量
文章目录 简介第一部分:超声波的简介工作原理1.发射超声波2.接收反射波3.计算时间差4.计算距离 硬件连接1.Trig2.Echo 示例代码代码说明注意事项1.声速2.延时精度3.硬件连接 第二部分:频率测量简介频率测量原理1.信号输入2.计数3.计算频率 硬件连接示例代…...

Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...

基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...
【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)
LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 题目描述解题思路Java代码 题目描述 题目链接:LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...