当前位置: 首页 > news >正文

优选算法的映射之妙:哈希表专题

专栏:算法的魔法世界

个人主页:手握风云

目录

一、哈希表简介

二、例题讲解

2.1. 两数之和

2.2. 判定是否互为字符重排

2.3. 存在重复元素

2.4. 存在重复元素 II

2.5. 字母异位词分组


一、哈希表简介

  • 哈希表

        哈希表(Hash Table)是一种高效的数据结构,通过 “键 - 值”(Key-Value)对的形式存储和检索数据。

  • 作用

        利用哈希函数将键映射到数组中的特定位置,从而实现快速查找、插入和删除操作。查找、插入、删除操作的时间复杂度均为 O(1),因为哈希函数能直接定位数据位置。

  • 什么时候用哈希表

        当我们需要频繁查找某一个元素的时候,效率非常高。

  • 怎么用哈希表

        在Java的集合框架中基于哈希表实现的HashMap和HashSet。但是新建哈希表和调用接口都是有时间消耗。如果说要处理的数据是字符,或者数据范围比较小的int型时,我们可以使用数据模拟哈希表。比如字符,我们可以利用ASCII码值映射到数组的下标。

二、例题讲解

2.1. 两数之和

        给定一个整数数组 nums 和一个整数目标值 target,在数组中找到和等于 target 的两个不同元素,返回这两个元素的数组下标

        这个题的暴力枚举思想很简单,先固定其中一个数,然后依次与前面的数字进行相加,这样能做到不重不漏。时间复杂度O(n^{2})

class Solution {public int[] twoSum(int[] nums, int target) {for (int i = nums.length - 1; i >= 0; i--) {for (int j = i - 1; j >= 0; j--) {if (nums[i] + nums[j] == target) {return new int[]{i ,j};}}}return new int[0];}
}

        接下来使用哈希表进行优化:当我们固定nums[i]的时候,我们需要在前面寻找target - nums[i],那我们就可以先遍历数组,把数组元素丢进哈希表,再让指针向后移动,如果能找到target - nums[i],就直接返回下标,没找到就继续向后移动。我们还需要判断一种情况,就是如果x == target - nums[i],就会自己找到自己。

        完整代码实现:

class Solution {public int[] twoSum(int[] nums, int target) {Map<Integer,Integer> hash = new HashMap<>();for (int i = 0; i < nums.length; i++) {int x = target - nums[i];if (hash.containsKey(x)) {return new int[]{i, hash.get(x)};}hash.put(nums[i],i);}return new int[]{-1, -1};}
}

2.2. 判定是否互为字符重排

        判断其中一个字符串通过字符重新排列后,能否完全变成另一个字符串(即两字符串本质是 “字符组成与个数完全相同,仅顺序不同”)。

        如果两个字符串长度不相等,直接返回false。我们可以先枚举出s1所有的重排结果,再与s2进行比较,但这样的时间复杂度会达到指数级别。此时我们就可以利用哈希表来统计每个字符出现的次数,比较两个哈希表中每个字符出现的次数是否相同。这时我们就可以借助字符的ASCII码值,利用数组模拟哈希表。在此基础上,我们还可以优化,只利用一个哈希表就行:先遍历字符串s1,将s1中的字符丢进哈希表,再去遍历s2,出现的字符则减少,如果hash[s2.charAt(i) - 'a'] < 0,返回false。

class Solution {public boolean CheckPermutation(String s1, String s2) {if (s1.length() != s2.length()) {return false;}int[] hash = new int[26];// 统计s1中每个字符出现的次数for (int i = 0; i < s1.length(); i++) {hash[s1.charAt(i) - 'a']++;}for (int i = 0; i < s2.length(); i++) {hash[s2.charAt(i) - 'a']--;if (hash[s2.charAt(i) - 'a'] < 0) {return false;}}return true;}
}

2.3. 存在重复元素

        判断数组中是否存在重复元素。

        创建一个哈希表,遍历数组,如果哈希表中存在该元素,返回true;没有,则丢进哈希表。

        完整代码实现:

class Solution {public boolean containsDuplicate(int[] nums) {Set<Integer> set = new HashSet<>();for (int i : nums) {if (set.contains(i)) {return true;}set.add(i);}return false;}
}

2.4. 存在重复元素 II

        与上一题不同的是,找出相等元素,索引距离不超过 k。

        遍历数组,如果哈希表中不存在该元素,则将它本身和下标一起丢进哈希表中,如果存在,在判断索引距离是否<=k。如果后面还存在重复元素,我们可以直接覆盖,因为我们要找的是距离最近的重复元素。

        完整代码实现:

class Solution {public boolean containsNearbyDuplicate(int[] nums, int k) {Map<Integer, Integer> map = new HashMap<Integer, Integer>();int length = nums.length;for (int i = 0; i < length; i++) {int num = nums[i];if (map.containsKey(num) && i - map.get(num) <= k) {return true;}map.put(num, i);}return false;}
}

2.5. 字母异位词分组

        给定一个字符串数组,需将其中的字母异位词(字母种类、数量完全相同,仅排列顺序不同的字符串)归为一组,最终返回包含所有分组的列表。

        我们需要先判断这些单词是否为字母异位词,我们这里可以我们利用字符的ASCII码值进行排序。对于字符串的分组,我们可以将哈希表的键值对类型定义为HashMap<String, List<String>>,遍历完一个字符串,符合要求,直接丢进新创建的顺序表中。

        完整代码实现:

class Solution {public List<List<String>> groupAnagrams(String[] strs) {Map<String, List<String>> hash = new HashMap<>();for (String s : strs) {char[] tmp = s.toCharArray();// 对字符数组进行排序,这样字母异位词就会变成相同的字符串Arrays.sort(tmp);String key = new String(tmp);if (!hash.containsKey(key)) {// 将字符串添加到对应分组hash.put(key, new ArrayList<>());}hash.get(key).add(s);}return new ArrayList<>(hash.values());}
}
http://www.xdnf.cn/news/1427239.html

相关文章:

  • 【数据结构】八大排序之快速排序:分而治之的艺术
  • 从技术架构到经济价值:低代码在企业开发中的成本节约潜力
  • 面试新纪元:无声胜有声,让AI成为你颈上的智慧伙伴
  • Windows远程连接:SSH+RDP+Server
  • 警惕!虚拟货币“赠予”可能被认定为洗钱犯罪
  • NLP模型简介
  • 解决Mac电脑连接蓝牙鼠标的延迟问题
  • 【Python练习题】Python小白必练100题答案-第21-40题
  • 基础思想:动态规划与贪心算法
  • [Dify 专栏] 如何通过 Prompt 在 Dify 中模拟 Persona:即便没有专属配置,也能让 AI 扮演角色
  • 文章阅读与实践 - 延迟双删/分库分表/Spring IOC生命周期/Mysql主从一致优化
  • 一文读懂 LoRaWAN A、B、C类的区别及应用
  • 用 PyTorch 实现食品图像分类:从数据预处理到模型训练与预测
  • Linux电脑怎样投屏到客厅的大电视?支持远程投屏吗?
  • 从Java全栈到前端框架:一场真实的技术面试实录
  • 《Vue进阶教程》(7)响应式系统介绍
  • iOS15如何绕过MDM锁?详细图文教程教你搞定
  • 滚珠导轨在工业制造领域如何实现高效运行?
  • 网络传输的实际收发情况及tcp、udp的区别
  • 电子电气架构 --- 当前企业EEA现状(上)
  • 云计算学习笔记——Linux系统网络配置与远程管理(ssh)篇
  • Java搭建高效后端,Vue打造友好前端,联合构建电子采购管理系统,实现采购流程电子化、自动化,涵盖采购全周期管理,功能完备,附详细可运行源码
  • Node.js 命令行交互王者:inquirer 模块实战指南
  • Pytorch Yolov11目标检测+window部署+推理封装 留贴记录
  • WPF迁移avalonia之图像处理(一)
  • 基于SpringBoot的古典舞在线交流平台
  • C++革命性新特性:默认实例导出(exportDefault)让单例模式变得无比简单!
  • Redis 缓存雪崩实战:从监控告警到3层防护的完整修复
  • Docker镜像指南:从核心命令到离线迁移实战
  • ⸢ 肆 ⸥ ⤳ 默认安全:安全建设方案 ➭ a.信息安全基线