Leetcode刷题-哈希表详细总结(Java)

哈希表

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

  • 数组
  • set (集合)
  • map(映射)

当我们遇到了要快速判断⼀个元素是否出现集合⾥的时候,就要考虑哈希法。如果在做⾯试题⽬的时候遇到需要判断⼀个元素是否出现过的场景也应该第⼀时间想到哈希法!

这一部分的题就是需要注意,如果用到了set,map,在定义的时候需要用包装类,也就是引用数据类型,而不是基本数据类型

0、泛型不能直接使用基本数据类型!!!

例如 intdoublechar 等。但是 Java 提供了对应的包装类来解决这个问题,例如 IntegerDoubleCharacter 等。所以,你可以在泛型中使用这些包装类来代替基本数据类型。

​ 例如,你可以使用 Integer 代替 intDouble 代替 doubleCharacter 代替 char,以及其他包装类来替代其他基本数据类型。

// byte 对应 Byte
// short 对应 Short
// int 对应 Integer
// long 对应 Long
// float 对应 Float
// double 对应 Double
// char 对应 Character
// boolean 对应 Boolean

1、有效的字⺟异位词(数组哈希表)

242. 有效的字母异位词 - 力扣(LeetCode)

其实就是不能出现一个字母只在前面出现,但是没在后面那个字符串中。并且需要 st 中每个字符出现的次数都相同

在这里插入图片描述

可以用数组,遍历字符串,然后设一个数组,hash[26],每遍历到一个字母,相应位置加1,之后遍历第二个字符串,遍历到对应字母就去减1,然后看最后这个hash中有无负值

public boolean isAnagram(String s, String t) {int[] hash = new int[26];for(int i = 0; i < s.length(); i++){hash[s.charAt(i) - 'a']++;   // 并不需要记住字符a的ASCII,只要求出⼀个相对数值就可以了}for(int i = 0; i < t.length(); i++){hash[t.charAt(i) - 'a']--;}for(int i = 0; i < 26; i++){if(hash[i] != 0)return false;}return true;
}

2、两个数组的交集(set)

349. 两个数组的交集 - 力扣(LeetCode)

在这里插入图片描述

一个set集合用于存放第一个数组中的元素,另外一个用于在遍历第二个数组的时候,去查找如果有相同元素情况,就存放进去

之后结果数组的大小,就是基于第二个set集合的大小new出来的。并且遍历第二个set集合,将里面的元素放进最终数组里。

public int[] intersection(int[] nums1, int[] nums2) {HashSet<Integer> set = new HashSet<Integer>();HashSet<Integer> result = new HashSet<Integer>();for(int i = 0; i < nums1.length; i++){set.add(nums1[i]);}for(int i = 0; i < nums2.length; i++){if(set.contains(nums2[i]))result.add(nums2[i]);}int[] res = new int[result.size()];int n = 0;for(int num: result){res[n++] = num;}return res;
}

3、两数之和(HashMap)

1. 两数之和 - 力扣(LeetCode)

在这里插入图片描述

这道题需要明确借助map的话,key和value分别存放什么

因为我们是需要基于数组值去查询的,所以key存放的是数组值,value存放的是对应的索引

在遍历数组的时候,只需要向map去查询是否有和⽬前遍历元素匹配的数值,如果有,就找到的匹配对,如果没 有,就把⽬前遍历的元素放进map中,因为map存放的就是我们访问过的元素。

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

4、四数相加

454. 四数相加 II - 力扣(LeetCode)

在这里插入图片描述

这题和四数之和的区别在于,这是四个数组,所以不需要考虑去重,因为四个数组是独立的,而四数之和问题是针对于一个数组。会可能结果出现重复的

本题的思路

将四个数组两两划分到一组

  1. 遍历⼤A和⼤B数组,统计两个数组元素之和(key),和出现的次数(value),放到map中。
  2. 定义int变量count,⽤来统计 a+b+c+d = 0 出现的次数。
  3. 在遍历⼤C和⼤D数组,找到如果 0-(c+d) 在map中出现过的话,就⽤count把map中key对应的value也就是出现次数统计出来。注意value是多少,那说明就出现过几次四数之和是这个目标target值的情况
  4. 最后返回统计值 count 就可以了
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {HashMap<Integer,Integer> map = new HashMap<Integer, Integer>();int count = 0;int n;for(int i = 0; i < nums1.length; i++){for(int j = 0; j < nums2.length; j++){if(map.get(nums1[i] + nums2[j]) == null)n = 1;elsen = map.get(nums1[i] + nums2[j])+1;map.put(nums1[i] + nums2[j],n++);}}for(int i = 0; i < nums3.length; i++){for(int j = 0; j < nums4.length; j++){int tmp = 0 - nums3[i] - nums4[j];if(map.containsKey(tmp))count += map.get(tmp);}}return count;
}
  • 这个题在写代码时候,需要注意,在填充次数的时候,由于Integer不存在0的情况,只是null

  • 这是和int基本数据类型的一大区别,所以我们需要判断他是不是本身不存在,然后赋值

5、三数之和

15. 三数之和 - 力扣(LeetCode)

在这里插入图片描述

首先想到哈希解决,可以用两个for循环,然后判断出来是不是存在一个key = 【0-a-b】

但是这个就有一个问题,会有重复的三元组,需要去重

因此,这里选择用另外一种方法:双指针法,会更高效一点

  • 由于我们需要返回值,不用返回下标,所以可以提前对数组进行排序

  • 之所以排序,因为我们的思路是让 i 去遍历数组,然后left首先指向【i+1】的位置,right指向最后一个位置

  • 如果nums[ i ] + nums[ left ] + nums[ right ] > 0;这时候如果排过序,可以让right–。就类似这样的操作。并且如果nums[ i ]本身就是大于0的,那就可以不用找了,因为left 和 right只会更大

  • 也需要进行去重

    1. 需要判断nums[ i ] == nums[ i - 1 ],因为如果之前一个元素和当前位置元素相同,那他获取到的结果,会和我们此次获取到的结果有重复情况,注意必须是判断当前元素和前一个元素,而不是和后一个元素nums[ i + 1 ]相比
    2. 在收获了一个三元组之后需要对于left指针部分去重:在left++之前,如果nums[ left ] ==nums[ left+1 ],就持续left++【用while判断】
    3. 在收获了一个三元组之后需要对于left指针部分去重:在right–之前,nums[ right ] == nums[ right-1 ],就持续right–【用while判断】

在这里插入图片描述

public List<List<Integer>> threeSum(int[] nums) {int n = nums.length;Arrays.sort(nums);List<List<Integer>> result = new ArrayList<List<Integer>>();// 找出a + b + c = 0// a = nums[i], b = nums[left], c = nums[right]for(int i = 0; i < n; i++){if(nums[i] > 0)  // 排序后如果第一个元素已经大于零,无论如何组合都不可能凑成三元组,直接返回结果就可以了return result;if(i > 0 && nums[i] == nums[i-1]) // 去重acontinue;int left = i + 1;int right = n - 1;while(left < right){if(nums[i] + nums[left] + nums[right] > 0)right--;else if(nums[i] + nums[left] + nums[right] < 0)left++;else{List<Integer> list = new ArrayList<Integer>();list.add(nums[i]);list.add(nums[left]);list.add(nums[right]);result.add(list);// 去重逻辑应该放在找到一个三元组之后,对b 和 c去重  一定要用while不是用if!!!!!!!while (right > left && nums[right] == nums[right - 1]) right--;while (right > left && nums[left] == nums[left + 1]) left++;right--;   //别忘了上面只是判断,这里才是真正的移动!!!!!!left++;}}}return result;
}

6、四数之和

18. 四数之和 - 力扣(LeetCode)

和三数之和一样,都是在一个数组上寻找四个元素的和等于target值,并且要求结果里面不能有重复的四元组结合

基本思路:

在三数之和的思路上,外面再加上一层for循环

这里的剪枝和对nums[ k ]的去重稍微有点不一样,因为这次是和target手动输入的值作比较,不像三数之和是单纯的和零做比较

public List<List<Integer>> fourSum(int[] nums, int target) {List<List<Integer>> result = new ArrayList<>();Arrays.sort(nums);  for (int k = 0; k < nums.length; k++) {// nums[i] > target 直接返回, 剪枝操作if (nums[k] > 0 && nums[k] > target) {return result;}if (k > 0 && nums[k - 1] == nums[k]) {    // 对nums[i]去重continue;}for (int i = k + 1; i < nums.length; i++) {if (i > k + 1 && nums[i - 1] == nums[i]) {  // 对nums[j]去重continue;}int left = i + 1;int right = nums.length - 1;while (right > left) {// nums[k] + nums[i] + nums[left] + nums[right] > target int会溢出long sum = (long) nums[i] + nums[k] + nums[left] + nums[right];if (sum > target) {right--;} else if (sum < target) {left++;} else {result.add(Arrays.asList(nums[i], nums[k], nums[left], nums[right]));// 对nums[left]和nums[right]去重while (right > left && nums[right] == nums[right - 1]) right--;while (right > left && nums[left] == nums[left + 1]) left++;left++;right--;}}}}return result;
}

基于代码随想录的学习,同时刷题总结哈希表的常用思路以及一些刷题笔记

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

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

相关文章

SpringCloud学习(11)-SpringCloudAlibaba-Nacos数据模型

一、Nacos数据模型 1.1、数据模型 对于Nacos配置管理&#xff0c;通过Namespace、Group、Date ID能够定位到一个配置集。Nacos数据模型如下所示&#xff1a; 1.2、命名空间(Namespace) 可用于进行不同环境的配置隔离。例如&#xff1a; 1)、可以隔离开发环境——测试环境和…

【Linux】进程学习① (进程的PCB(task_struct)进程的标识符详解进程的创建fork函数)

目录 ​编辑 1.进程的概念 1.1进程的描述与组织&#xff1a;进程的PCB 进程&#xff1a;进程是 内核pcb对象可执行程序/内核数据结构可执行程序进程 1.3 task_struct 2.PCB内部属性 3 查看进程 4.获取进程标识符&#xff1a;getpid函数&#xff08;4-6主要围绕进程的标识符展开…

全系统各类型工程水土保持方案编制

孙老师&#xff08;高级工程师&#xff09;&#xff1a;长期承担重点水土保持方案编写方面工作&#xff0c;开设多场线下、线上培训会议&#xff0c;拥有丰富的工程和教学经验&#xff0c;为众多单位培养了近千名水土保持骨干人员&#xff0c;建有多个技术交流群&#xff0c;长…

HCIP-Datacom(H12-821)题库补充(4月7日)

最新 HCIP-Datacom&#xff08;H12-821&#xff09;完整题库请扫描上方二维码访问&#xff0c;持续更新中。 在PIM-DM中&#xff0c;路由器会为被裁剪的下游接口启动一个剪枝定时器&#xff0c;定时器超时后接口就会恢复转发。默认情况下该定时器是多少秒&#xff1f; A&#x…

帧动画实践

帧动画 基本介绍动画帧率&#xff08;FPS&#xff09;帧动画开发帧动画的实现方案gif图实现动画css实现动画js实现逐帧动画&#xff08;1&#xff09;raf介绍&#xff08;2&#xff09;为什么建议raf&#xff08;定时器和Raf区别&#xff09;? 实现帧动画常用的解决方案 demo实…

通讯录----顺序表版本

1.通讯录的实现逻辑 对于通讯录&#xff0c;我们做的无非就是初始化&#xff0c;销毁。添加联系人数据&#xff0c;修改联系人数据&#xff0c;删除联系人数据&#xff0c;查找联系人数据&#xff0c;展示联系人数据&#xff1b; 这个不就和我们的顺序表的逻辑如出一辙吗&…

Lesson1--数据结构前言

1. 什么是数据结构&#xff1f; 2. 什么是算法&#xff1f; 3. 数据结构和算法的重要性 4. 如何学好数据结构和算法 5. 数据结构和算法书籍及资料推荐 1. 什么是数据结构&#xff1f; 数据结构(Data Structure) 是计算机存储、组织数据的方式&#xff0c;指相互之间存在一…

虚拟机 ubuntu 20.04 git 设置代理的方法

前言 ubuntu 20.04 虚拟机中 Git 访问 github 或者其他的 git 仓库&#xff0c;大部分情况下速度很慢&#xff0c;并且容易掉线 如果 主机上使用了代理软件&#xff0c;但是虚拟机 ubuntu 中 Git 访问 git 仓库依旧是很慢 【问题】如何设置 虚拟机 ubuntu 的 Git 代理&#x…

从概念到实践:探索独立站在当代电商中的关键作用

随着数字化时代的到来&#xff0c;电子商务已成为全球商业生态的核心组成部分。在这个不断变化的市场中&#xff0c;独立站作为企业建立在线身份和拓展业务的强大工具&#xff0c;正逐步展现出其不可替代的价值。 从概念到实践&#xff0c;本文将深入探索独立站在当代电商中的关…

vivado 系统内逻辑设计调试流程

系统内逻辑设计调试流程 Vivado 工具提供了诸多功能 &#xff0c; 用于在真实硬件器件中调试系统内设计。系统内调试流程包含 3 个不同阶段 &#xff1a; 1. 探测阶段 &#xff1a; 确定设计中要探测的信号和探测的方法。 2. 实现阶段 &#xff1a; 完成设计实现 &…

Redis的主从复制和哨兵模式

目录 引言 一、主从复制 1.1 概念 1.2 作用 1.3 流程 1.4 环境搭建 二、哨兵模式 2.1 概念 2.2 原理 2.3 作用 2.4 故障转移机制 2.5 主节点的选举 2.6 环境搭建 2.6.1 修改Redis 哨兵模式的配置文件(所有节点操作) 2.6.2 启动哨兵模式 2.6.3查看哨兵信息 2.6.…

SystemC入门学习Demo用例的工程化配置

背景&#xff1a;对不同的用例文件&#xff0c;使用CMakeLists.txt进行工程化管理的演示&#xff0c;这样开发者可以更加关注在代码开发上。 1&#xff0c;首先安装好系统环境的systemC库&#xff1a;ubuntu系统安装systemc-2.3.4流程-CSDN博客 2&#xff0c;准备好一个demo用…