文章目录

  • 哈希表
    • 1.原理
    • 2.复杂度分析
  • 题目&推荐列表
  • 哈希集合的应用
    • 0.常用解题模板
    • 1.lc217 存在重复元素
    • 2.lc136 只出现一次的数字
    • 3.快乐数
  • 哈希映射的应用
    • 0.常用解题模板
    • 1. lc1 两数之和
    • 2. lc387 字符串中的第一个唯一字符
    • 3. lc350 两个数组的交集II
    • 4. lc219 存在重复元素II
    • 5.lc13 罗马数字转整数
    • 6. lc1207 独一无二的出现次数
    • 7. lc1365 有多少小于当前数字的数字

哈希表

哈希表是一种使用哈希函数组织数据,以支持快速插入和搜索的数据结构

有两种不同类型的哈希表:哈希集合和哈希映射。

  • 哈希集合是集合数据结构的实现之一,用于存储非重复值。
  • 哈希映射是映射 数据结构的实现之一,用于存储(key, value)键值对。

1.原理

简单介绍下:
哈希表的关键思想是使用哈希函数将键映射到存储桶。更确切地说

  • 当插入一个新的键时,哈希函数将决定该键应该分配到哪个桶中,并将该键存储在相应的桶中;
  • 当想要搜索一个键时,哈希表将使用相同的哈希函数来查找对应的桶,并只在特定的桶中进行搜索

更深层次的底层原理以及如何设计哈希集合和哈希映射,可以参见 HashSet底层原理分析

lc705设计哈希集合
lc706设计哈希映射

2.复杂度分析

典型的空间换时间,查找的时间复杂度是O(1),空间复杂度是O(n)

题目&推荐列表

本文题目

题号&链接 分类/标签 难度
1. lc217 存在重复元素 哈希集合 easy
2. lc316 只出现一次的数字 哈希集合, 哈希映射 easy
3. lc202快乐数 哈希集合,快慢指针 easy
4.lc1 两数之和 哈希映射 easy
5.lc387 字符串中的第一个唯一字符 哈希映射 easy
6.lc350两个数组的交集II 哈希映射 easy
7.lc219存在重复元素II 哈希映射 easy

推荐习题

题号&链接 分类/标签 难度 题解链接
1. lc349 两个数组的交集 两个哈希集合 easy 题解
2. lc287 寻找重复数 哈希集合,快慢指针 medium 题解
3. lc137 只出现一次的数字II 哈希集合 medium 题解
4. lc260 只出现一次的数字III 哈希表,位运算 medium 题解
5. lc599两个列表的最小索引和 哈希映射 easy 题解
6. lc205同构字符串 哈希映射 easy 题解
7. lc383 赎金信 哈希映射(数组) easy 题解
8. lc15 三数之和 排序+双指针 medium 题解

注:排序+双指针在有关哈希题目中经常可以达到奇效(包括后面的四数之和,四数相加,用哈希来做其实复杂度就很高了)

哈希集合的应用

哈希集是集合的实现之一,它是一种存储不重复值的数据结构;

所以可以 使用哈希集合来查重。

注意的几个点是:
1.底层数据结构是哈希表 ;2.没有带索引的方法;3.不包含重复元素

对于哈希集合(HashSet)用法还不熟悉的可以看看这篇 HashSet基础入门

这里还是回顾一下主要方法:

方法 含义
boolean add(E object) 增加元素
void clear() 清楚所有元素
boolean contains(Object object) 判断集合是否含有特定元素object
boolean isEmpty() 判断集合是否为空
boolean remove(Object object) 删除元素
int size() 计算集合大小

0.常用解题模板

(仅供参考)

// 利用HashSet查重
boolean findDuplicates(List<T> keys) {// 首先创建一个哈希集合,T表示实际中的数据类型Set<T> hashset = new HashSet<>();// 对给定的集合或者列表进行遍历for (T key : keys) {if (hashset.contains(key)) {return true;}hashset.add(key);}return false;
}

1.lc217 存在重复元素

力扣217链接

描述:

给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 ,返回 true ;如果数组中每个元素互不相同,返回 false

示例:

输入:nums = [1,2,3,1] 输出:true

Solution:

典型的查重,运用Set的去重性(与模板高度相似)

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

2.lc136 只出现一次的数字

力扣136链接

描述:

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

示例:

输入: [4,1,2,1,2] 输出: 4

Solution 1: 哈希集合

public static int singleNumber1(int[] nums) {// 使用集合存储数字Set<Integer> set = new HashSet<>();// 遍历数组中的每个数字for (int num:nums) {// 如果集合中没有该数字,则将该数字加入集合if (!set.contains(num))set.add(num);// 如果集合中已经有该数字,则将该数字从集合中删除  elseset.remove(num);}// 最后剩下的数字就是只出现一次的数字return set.iterator().next();
}

Solution2:哈希映射
注意,和次数相关的题目第一反应要想到哈希映射!

public static int singleNumber2(int[] nums) {// 使用哈希表存储每个数字和该数字出现的次数Map<Integer, Integer> map = new HashMap<>();// 遍历数组即可得到每个数字出现的次数,并更新哈希表for (int num : nums) {int count = 1;if (map.containsKey(num)) {count++;map.put(num, count);// 可以直接用map.put(num,map.getordefault(x,0)+1)}map.put(num, count);}// 最后遍历哈希表,得到只出现一次的数字for (Integer key : map.keySet()) {if (map.get(key) == 1)return key;}return -1;

Solution 3:位运算(官方)
时间复杂度O(n),空间复杂度O(1)

 public static int singleNumber3(int[] nums) {// 相同的数异或为0,异或具有交换律int res = nums[0];for (int i = 1; i < nums.length; i++) {res = res ^ nums[i];}return res;}

3.快乐数

力扣202链接

描述:

编写一个算法来判断一个数 n 是不是快乐数。「快乐数」 定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和;然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1;如果这个过程 结果为 1,那么这个数就是快乐数。

示例:

输入:n = 19 输出:true

Solution :
哈希集合,判断每一次新数的总和是否重复

public boolean isHappy(int n) {Set<Integer> record = new HashSet<>();// 利用 HashSet 的去重性while (n != 1 && !record.contains(n)) {record.add(n);n = getNextNumber(n);}return n == 1;}
// 先去求下一个新数
private int getNextNumber(int n) {int res = 0;while (n > 0) {int temp = n % 10;res += temp * temp;n = n / 10;}return res;}

哈希映射的应用

使用哈希映射的第一个场景是,我们需要更多的信息,而不仅仅是键。然后通过哈希映射建立key与value之间的映射关系。

对HashMap主要方法还不熟悉的可以参考这篇文章,HashMap基础入门,有对方法的解释和方法运用的示例。

0.常用解题模板

(仅供参考)

场景1:提供更多信息

ReturnType aggregateByKey_hashmap(List<Type>& keys) {// Replace Type and InfoType with actual type of your key and valueMap<Type, InfoType> hashmap = new HashMap<>();for (Type key : keys) {if (hashmap.containsKey(key)) {if (hashmap.get(key) satisfies the requirement) {return needed_information;}}// Value can be any information you needed (e.g. index)hashmap.put(key, value);    }return needed_information;
}

场景2:按键聚合

ReturnType aggregateByKey_hashmap(List<Type>& keys) {// Replace Type and InfoType with actual type of your key and valueMap<Type, InfoType> hashmap = new HashMap<>();for (Type key : keys) {if (hashmap.containsKey(key)) {hashmap.put(key, updated_information);}// Value can be any information you needed (e.g. index)hashmap.put(key, value);    }return needed_information;
}

1. lc1 两数之和

力扣1链接

描述:

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那两个整数,并返回它们的数组下标

示例:

输入:nums = [2,7,11,15], target = 9 输出:[0,1]

Solution:

public int[] twoSum(int[] nums, int target) {// 创建一个HashMapMap<Integer,Integer> map  = new HashMap<>();// 创建一个数组,用来存储结果的两个下标int[] res = new int[2];for(int i=0;i<nums.length;i++){// tmp的含义是当前的整数所需匹配的数字,如扫描到2需要的是7(9-2)int tmp = target-nums[i];// 判断hashmap中是否存在tmp的keyif(map.containsKey(tmp)){/*存在这个值为tmp的key就说明此时的i肯定是其中一个索引,另一个索引是以tmp为key的value值*/res[0]=i;res[1]=map.get(tmp);}// 表示不存在这样的key,所以将当前数字和其下标添加到map中map.put(nums[i],i);}return res;}

2. lc387 字符串中的第一个唯一字符

力扣387链接

描述:给定一个字符串 s ,找到它的第一个不重复的字符,并返回它的索引 。不存在,返回 -1
示例:输入: s = “loveleetcode” 输出: 2

Solution1:哈希映射
使用哈希表存储频数。先用map存储字符出现的次数;然后遍历string,如果在map中找到了次数为1的时候就返回就返回对应的下标

class Solution {public int firstUniqChar(String s) {Map<Character, Integer> frequency = new HashMap<Character, Integer>();for (int i = 0; i < s.length(); ++i) {char ch = s.charAt(i);frequency.put(ch, frequency.getOrDefault(ch, 0) + 1);}for (int i = 0; i < s.length(); ++i) {if (frequency.get(s.charAt(i)) == 1) {return i;}}return -1;}
}

Solution2:数组
数组实现哈希映射(时间上要快很多)

public static int firstUniqChar(String s) {int[] a = new int[26];for(int i=0;i<s.length();i++){char chs = s.charAt(i);a[chs-'a'] ++;}for(int i=0;i<s.length();i++){char chs = s.charAt(i);if(a[chs-'a']==1)return i;}return -1;

3. lc350 两个数组的交集II

力扣350链接

(有II肯定有I,可以先做I,lc349 两个数组的交集)

描述:

给你两个整数数组 nums1 和 nums2,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。

示例:

输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[4,9]

Solution:
哈希映射

在这里插入代码片

4. lc219 存在重复元素II

力扣219链接

描述:给你一个整数数组 nums 和一个整数 k ,判断数组中是否存在两个 不同的索引 i 和 j ,满足 nums[i] == nums[j] 且 abs(i - j) <= k 。如果存在,返回 true ;否则,返回 false
示例:
输入:nums = [1,2,3,1], k = 3 输出:true

Solution:

public boolean containsNearbyDuplicate(int[] nums, int k) {Map<Integer,Integer> map = new HashMap<>();for(int i=0;i<nums.length;i++){int tmp = nums[i];// 判断当前tmp是否存在与hashmap中,且要满足当前索引与之前索引差值不大于kif(map.containsKey(tmp) && i-map.get(tmp)<=k) {return true;}//如果不满足要求,就把当前元素存入hashmap中map.put(tmp,i);}return false;

5.lc13 罗马数字转整数

描述:给定一个罗马数字,将其转换成整数。
示例:输入: s = “III” 输出: 3 输入: s = “IX” 输出: 9

Solution:
用一个哈希表建立映射。然后遍历给定的字符串,判断左右罗马数字的大小,如果左边的比右边的小,就减去这个数,反之就加上。

 public int romanToInt(String s) {Map<Character,Integer> helper = new HashMap<>();helper.put('I',1);helper.put('V',5);helper.put('X',10);helper.put('L',50);helper.put('C',100);helper.put('D',500);helper.put('M',1000);int len = s.length();int value=0;  // 记录最后的整数for(int i=0;i<len;i++){int num = helper.get(s.charAt(i)); //获取罗马数字代表的整数// 判断是加还是减if(i<len-1 && num<helper.get(s.charAt(i+1))) value -= num;elsevalue += num;}return value;}

时间复杂度:O(n),其中 n 是字符串 s 的长度。空间复杂度:O(1)

6. lc1207 独一无二的出现次数

力扣1207链接

描述:给你一个整数数组 arr,请你帮忙统计数组中每个数的出现次数。
如果每个数的出现次数都是独一无二的,就返回 true;否则返回 false。
输入:arr = [1,2,2,1,1,3] 输出:true

Solution:
看到次数,想到哈希法。。。

(本题第一反应是用哈希映射,如果想要时间效率更高,应该采取数组来进行哈希映射)

public boolean uniqueOccurrences(int[] arr) {HashMap<Integer,Integer> map = new HashMap<>();for(int num:arr){map.put(num,map.getOrDefault(num,0)+1);}Set<Integer> set = new HashSet<>();for(int value:map.values()){if(set.contains(value))return false;elseset.add(value);}return true;}

7. lc1365 有多少小于当前数字的数字

力扣1365链接

描述:

给你一个数组 nums,对其中每个元素 nums[i],请你统计数组中比它小的所有数字的数目
输入:nums = [8,1,2,2,3] 输出:[4,0,1,1,3]

solution:
第一眼,真想暴力,两层for直接跑路~

冷静一下,仔细想想,还得是哈希(先排序后哈希,哈希用来做数值和下标的映射)

 public int[] smallerNumbersThanCurrent(int[] nums) {HashMap<Integer,Integer> map = new HashMap<>();int[] res = Arrays.copyOf(nums,nums.length);Arrays.sort(res);for(int i=0;i<nums.length;i++){if(!map.containsKey(res[i])){map.put(res[i],i);}}for(int i=0;i<res.length;i++){res[i] = map.get(nums[i]);}return res;}

参考链接:
https://leetcode.cn/leetbook/read/hash-table/

LeetCode哈希表(哈希集合,哈希映射)相关推荐

  1. 【哈希表】(一) 设计哈希表

    目录 一.设计哈希表 二.设计哈希表的关键 三.设计哈希集合 3.1 题目要求 3.2 解决过程 四.设计哈希映射 4.1 题目要求 4.2 解决过程 五.设计哈希表 - 解决方案 六.复杂度分析 - ...

  2. 哈希表题目:设计哈希映射

    文章目录 题目 标题和出处 难度 题目描述 要求 示例 数据范围 前言 解法一 思路和算法 代码 复杂度分析 解法二 思路和算法 代码 复杂度分析 题目 标题和出处 标题:设计哈希映射 出处:706. ...

  3. 在java中 哈希表会经常出现哈希碰撞吗

    在Java中,哈希表可能会经常出现哈希碰撞.哈希表是一种根据键(Key)来访问值(Value)的数据结构,通过哈希函数将键映射到哈希表的索引位置上.由于哈希函数的映射结果可能不唯一,不同的键可能会被映 ...

  4. 什么是哈希表?什么又是哈希冲突?哈希冲突的解决方法?

    首先,什么是哈希表?什么又是哈希冲突? ①哈希表是基于数组的一种存储方式.它主要由哈希函数和数组构成.当要存储一个数据的时候,首先用一个函数计算数据的地址,然后再将数据存进指定地址位置的数组里面.这个 ...

  5. C#中的集合、哈希表、泛型集合、字典

    集合ArrayList 集合:集合可以看做是数组,可以将其看成"长度可变,具有很多方法的数组".使用ArrayList,首先需要导入命名空间using.system.collect ...

  6. 基础数据结构(二):字典树、并查集、堆、哈希表、字符串的哈希方式、STL的常见容器及其接口

    文章目录 一.字典树Trie 1 原理 2 Trie字符串统计 3 [LeetCode 208. 实现 Trie (前缀树)](https://leetcode-cn.com/problems/imp ...

  7. 哈希表数据结构_Java数据结构哈希表如何避免冲突

    前言 一.哈希表是what? 这是百度上给出的回答: 简而言之,为什么要有这种数据结构呢? 因为我们想不经过任何比较,一次从表中得到想要搜索的元素.所以就构造出来了哈希表,通过某种函数(哈希函数)使元 ...

  8. e - 数据结构实验之查找五:平方之哈希表_leetcode算法之哈希表

    今天该来盘一盘 哈希表 这类题目 分类别解析leetcode上的一些相关的例题路,代码采用C++与python实现. 哈希表 哈希表是一种很有用的数据结构, 其作用主要是以空间换时间, 在c++中主要 ...

  9. c++ map 修改value_哈希表:其实需要哈希的地方都能找到map的身影

    给「代码随想录」一个星标吧! ❝ 数组和set都靠边站! ❞ 第454题.四数相加II 给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A ...

  10. python 哈希表_数据结构-7 哈希表

    python内部查找表非常快,就是用的哈希表(hash-table)实现的. 后续实现字典集合. 怎么解决冲突? 其实一种直观的想法是如果冲突了我能不能让数组中 对应的槽变成一个链式结构呢?这就是其中 ...

最新文章

  1. 关于微信小程序登录授权
  2. Zepto源码分析-架构
  3. 今晚直播 | 清华大学​高天宇:对比学习及其在NLP中的应用
  4. pandas基本数据处理
  5. boost::histogram::algorithm::project用法的测试程序
  6. Linux系统下Configure命令参数解释说明
  7. NSubstitute完全手册(一)入门基础
  8. HDOJ5547 SudoKu
  9. mac地址转换_mac电脑格式转化工具
  10. 内容生态搜索趋势研究报告
  11. 庆功会(信息学奥数一本通-T1269)
  12. Perl文件处理示例——批量添加Copyright版权信息
  13. 黑马python培训视频网盘下载_黑马课堂大数据全套视频课程百度云下载
  14. 小程序毕设作品之微信酒店预订小程序毕业设计(6)开题答辩PPT
  15. AD教程系列 | 5 - 绘制原理图
  16. 处理器仿存带宽_CPU,内存,主板带宽是怎么计算的?网上帖子说内存和主板的带宽要大于等于CPU带宽,充分利用CPU...
  17. 干货 | 产品助理入门攻略(一枚入行3年的PM内心独白)
  18. oppo云服务器怎么卸载,oppo手机小布助手卸载方法_oppo手机小布助手怎么卸载-硬件之家...
  19. 基于spring mvc+bootstrap 集成的返利平台 新增内容-自动对接京东数据
  20. 阿里云视频云正式支持AV1编码格式 为视频编码服务降本提效

热门文章

  1. 这样的设计太妙了!K8S 神秘架构终于揭开面纱!
  2. 解决Ubuntu自动更新Linux内核导致显卡驱动无法加载,致使循环在登录界面
  3. 支付宝二面:如何用 UDP 实现可靠传输?
  4. Detect-SLAM阅读笔记
  5. 现代循环神经网络-1.门控循环单元(GRU)【动手学深度学习v2】
  6. 0基础软件测试小白,如何找到一份高薪的工作?
  7. IT项目管理画图题【太原理工大学】
  8. 几个常见的B端推广渠道
  9. java 中 webcam类_如何在Java的Swing应用程序中集成Webcam?
  10. 【Python】Python3如何将汉字转化成反斜线u(\u)开头的字符串