算法笔记——哈希表篇

news2024/12/22 19:36:43

一般哈希表都是用来快速判断一个元素是否出现集合里,哈希表并不意味着一定要使用HashMap,有时候使用数组更方便,有时候要使用set,依据具体情况而定,哈希表是典型的空间换时间。

在这里插入图片描述

数组作为哈希表

一些应用场景就是为数组量身定做的,最常见的是要求只有小写数组,最适合用数组作为哈希表

242.有效的字母异位词

该题让我们统计两个字符串中的字符是否数量一样,都是小写字母,直接用数组来统计最合适。

/**
 * 242. 有效的字母异位词 字典解法
 * 时间复杂度O(m+n) 空间复杂度O(1)
 */
class Solution {
    public boolean isAnagram(String s, String t) {
        int[] record = new int[26];

        for (int i = 0; i < s.length(); i++) {
            record[s.charAt(i) - 'a']++;     // 并不需要记住字符a的ASCII,只要求出一个相对数值就可以了
        }

        for (int i = 0; i < t.length(); i++) {
            record[t.charAt(i) - 'a']--;
        }
        
        for (int count: record) {
            if (count != 0) {               // record数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。
                return false;
            }
        }
        return true;                        // record数组所有元素都为零0,说明字符串s和t是字母异位词
    }
}

还有一道相似的题,与上一题的区别是a字符串中字符的数量要被b字符串包含

383. 赎金信

Set作为哈希表

力扣题目链接

349. 两个数组的交集

HashSet常用API:

  1. set.add() :用于往hashSet中添加元素
  2. set.remove():用于删除hashSet中的元素
  3. set.contains():用于判断这个元素在不在hashSet中

本题判断两个数组的交集,只要在一个数组中出现一次,就可以记录到hashSet中:

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        int length = nums1.length>nums2.length?nums2.length:nums1.length;
        int[] result = new int[length];
        int count = 0;
        HashSet<Integer> set = new HashSet<>();
        for (int i = 0; i < nums1.length; i++) {
            if (!set.contains(nums1[i])){
                set.add(nums1[i]);
            }
        }
        for (int i = 0; i < nums2.length; i++) {
            if (set.contains(nums2[i])){
                result[count++] = nums2[i];
                set.remove(nums2[i]);
            }
        }
          return Arrays.copyOfRange(result,0,count);
    }
}

Map作为哈希表

力扣题目链接:

1. 两数之和

HashMap常用API:

  1. map.put(key,value):存一个键值对
  2. map.get(key):根据key获取value
  3. map.containsKey():查找有没有对应的key
  4. map.getOrDefault(key,defaultValue):获得key对应的value,如果没有获得默认值

这种题目需要使用key value结构,单纯的Set已经不再适用。两数之和,存起来的key是target减去当前数组中的元素,value是对应的位置,这样到下一个元素,用当前元素的数值就可以判断有没有符合条件的结果了。

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer,Integer> map = new HashMap<>();
        for(int i=0;i<nums.length;i++){
            if(map.containsKey(nums[i])){
                int result1 = map.get(nums[i]);
                return new int[]{result1,i};
            }
            else{
                map.put(target-nums[i],i);  // 如果这个不是结果,存起来,key是target-当前值,value是当前值的位置
            }
        }
        return null;
    }
}

几数之和系列

几数之和类的题目不一定适合使用哈希表,有些用双指针加去重的方式比较好。

适用于使用哈希表的题

454. 四数相加 II

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

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

示例 1:

输入:nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2]
输出:2
解释:
两个元组如下:

  1. (0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0
  2. (1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0

由于本题是在四个数组中寻找满足四个数为0的元组数,不涉及去重问题,所以可以使用HashMap,前两个数组中的和作为放入map中,value是该和的出现次数,然后在第3、4个数组中 根据两个和的负数作为key去map中查,查到了就作为结果的一部分。

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
Map<Integer,Integer> map =new HashMap<>();
int result=0;
for (int i:nums1){
	for (int j:nums2){
map.put(i+j,map.getOrDefault(i+j,0)+1);
	}
}
for (int u:nums3){
	for (int v:nums4){
if (map.containsKey(-u-v)){
result+=map.get(-u-v);}
    }
}
return result;
    }
}

不适用哈希表,需要双指针加去重的

在几数之和类的题目中,如果是在一个数组中寻找几数之和,那么用哈希表的方法就比较麻烦,使用双指针(其实是多指针)外加考虑去重的方法是最好的。

步骤大概为:

  1. 将数组排序,想要后续去重,使用双指针,就一定要对数组排序。
  2. 遍历数组,三数之和就用一个索引外加两个指针遍历,四数之和就用两个索引外加两个指针遍历。
  3. 去重,每一个数都要去重,但是去重的规则是不一样的。

力扣题目:

15. 三数之和

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

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

注意:答案中不可以包含重复的三元组。

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。

本题使用哈希表来解决并不好做,因为要考虑去重的一系列问题,所以使用双指针法。

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        Arrays.sort(nums);  // 先给数组排序
        int left,right;  // 两个指针,一个索引,就是共计三个指针来确定三个数
        int len = nums.length;
        for(int i=0;i<len;i++){
            if(nums[i]>0){
                return result;
            }
            if(i>0 && nums[i]==nums[i-1]){ // a的去重
                continue;
            }
            left = i+1;
            right = len-1;
            while(left<right){
                if(nums[i]+nums[left]+nums[right]<0){
                    left++; 
                } else if(nums[i]+nums[left]+nums[right]>0){
                    right--;
                } else {
                    List<Integer> temp = new ArrayList<>();
                    temp.add(nums[i]);
                    temp.add(nums[left]);
                    temp.add(nums[right]);
                    result.add(temp);
                    while(left<right && nums[left] == nums[left+1]) left++;  // b,c的去重
                    while(left<right && nums[right] == nums[right-1]) right--; 
                    left++;
                    right--;
                }
              
            }
        }
        return result;

}
}

注意 a,b,c三个数的去重是有些不一样的,因为a是第一个数,要用nums[i]==nums[i-1]来判断重复,而不是判断i和i+1,就是不能判断下一个而是要判断上一个,为的就是怕(-1,-1,2)这种结果漏掉,只是结果不能重复,而不是结果里不能有重复的元素,但是b,c就没有这种限制,因为是后面的元素,如果b去重逻辑是判断i和i+1是可以的,因为c数在移动的时候会找到这个结果。不会漏掉。

力扣题目:

18. 四数之和

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

0 <= a, b, c, d < n
a、b、c 和 d 互不相同
nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。

示例 1:

输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]

class Solution {
    // 前两个数循环,后两个数双指针,都要去重,还要注意int类型溢出的问题
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> resultList= new ArrayList<>();
        Arrays.sort (nums);
        int length=nums.length;
        for(int i=0;i<length;i++){
            if(i>0&&nums[i]==nums[i-1]){
                continue;}
            for (int j=i+1;j<length-2;j++){
                if(j>i+1&&nums[j]==nums[j-1]){
                    continue;}
                int left =j+1;
                int right= length-1;
                while (left< right){
                    long sum = (long) nums[i] + nums[j] + nums[left] + nums[right];
                    if (sum == target){
                        List<Integer> temp =new ArrayList<>();
                        temp.add(nums[i]);
                        temp.add(nums[j]);
                        temp.add(nums[left]);
                        temp.add(nums[right]);
                        resultList.add(temp);
                        left++;
                        right--;
                        while (left<length&&nums[left]==nums[left -1]){
                            left++;}
                        while (right>0&&nums[right]==nums[right+ 1]){
                            right--;
                        }
                    }
                    else if(sum<target){
                        left++;}
                    else{
                        right--;}
                }
            }}
        return resultList;
    }
}

本题需要注意的地方:

  1. 去重时,第二位数也是需要判断前一位而不是后一位,因为(-1,-1,-1,3)这种数可能漏判,倒数第二位和倒数第一位就不用,和三数之和同理
  2. 注意int类型溢出,四个int相加可能超过int类型的限制,因此转化为long类型判断

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

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

相关文章

工具 | 应用程序无法启动,应为应用程序的并行配置不正确

工具 | 应用程序无法启动&#xff0c;应为应用程序的并行配置不正确 “E:\02-Doc\朱老师物联网大讲堂-全部视频\朱有鹏老师嵌入式linux核心课程\开发版光盘资料\X210V3S_A\tools\x210_Fusing_Tool.exe”的激活上下文生成失败。 找不到从属程序集 Microsoft.VC90.MFC,processorA…

DNS-去中心化域名系统,创建您在DeSoc 社会中的YUAN ID

传统域名系统 (DNS) 是一个分层的分散信息存储&#xff0c;用于将用户在网络浏览器中输入可读名称&#xff08;例如 www.baidu.com&#xff09;解析为IP地址&#xff0c;来访问互联网上的计算机。传统DNS使用一种分布式数据库&#xff0c;有严格的上下级关系&#xff0c;上级仅…

[Android JNI] --- JNIEnv和JavaVM

1 JVMEnv 1.1 JNIEnv 是什么 JNIEnv 即 Java Native Interface Environment&#xff0c;Java 本地编程接口环境。JNIEnv 内部定义了很多函数用于简化我们的 JNI 编程。 JNIEnv是提供JNI Native函数的基础环境&#xff0c;线程相关&#xff0c;不同线程的JNIEnv相互独立&#…

SpringBoot快速回顾(@value读取配置文件)

目录 1.定义配置文件2. 定义Controller类3. 测试4. 优化4.1 封装实体类4.3 定义controller类4.2 测试 本文将介绍如何使用value读取配置文件的内容。 在实际项目中&#xff0c;往往会在配置文件中写项目部署需要配置的环境信息&#xff08;数据库驱动&#xff0c;数据库账号密码…

医疗金融法律大模型:从ChatDoctor到FinBERT/FinGPT/BloombergGPT、ChatLaw/LawGPT_zh

第一部分 各种医疗类ChatGPT&#xff1a;或中英文数据微调LLaMA、或中文数据微调ChatGLM 1.1 基于LLaMA微调的中英文版ChatDoctor 1.1.1 ChatDoctor&#xff1a;通过self-instruct技术提示API的数据和医患对话数据集微调LLaMA Github上有一个基于LLaMA模型的医疗微调模型&am…

zabbix (自定义监控内容-配置邮件报警-自动发现与自动注册)

目录 zabbix 客户端主机配置自定义监控内容设置邮件报警zabbix 自动发现与自动注册zabbix 自动发现&#xff08;对于 agent2 是被动模式&#xff09;//zabbix 自动发现&#xff08;对于 agent2 是被动模式&#xff09;zabbix 自动注册&#xff08;对于 agent2 是主动模式&#…

IDEA+springboot+jpa+Layui+Mysql销售考评系统源码

IDEAspringbootjpaLayuiMysql销售考评系统源码 一、系统介绍1.环境配置 二、系统展示1. 管理员登录2.评分结果3.评分管理4.添加评分5.用户管理6.添加用户7.角色管理8.添加角色8.销售管理9.添加销售 三、部分代码UserDao.javaUserController.javaUser.java 四、其他获取源码 一、…

计算机组成原理实验二:多位逻辑门构建

目录 一、实验目的 二、实验设备 三、实验原理 四、实验内容 1. 16位非门 2.16位与门 3.16位或门 4. 16位复用器 五、实验习题 1.还可以怎样设计各种芯片的物理结构 2.“block copy”&#xff08;块复制&#xff09;和edit菜单中“copy to clipboard”的区别 六、自…

在线OJ项目

1.在线OJ-背景介绍 在线的网页版的编程平台.&#xff0c;打开一个网站,上面就能看到很多的算法题.&#xff0c;在线做题,在线提交.立即就能看到运行结果,是否通过. leetcode 牛客等 一个在线OJ平台,核心功能: 能够管理题目(保存很多的题目信息:题干&#xff0b;测试用例)题…

FPGA软核调试方法

软核工程创建步骤 创建如下工程目录 bin目录&#xff1a;存放SDK工程生成的elf文件(Release编译模式) hdf目录&#xff1a;存放fpga工程师提供的的hdf文件 prj目录&#xff1a;工程目录(包含SDK工程源码) doc目录&#xff1a;文档目录 基于2018.2版本SDK建立工程 打开Xil…

Spring Boot中的CSRF攻击及预防

Spring Boot中的CSRF攻击及预防 什么是CSRF攻击&#xff1f; CSRF&#xff08;Cross-site Request Forgery&#xff09;跨站请求伪造&#xff0c;也称为“one-click attack”或“session riding”&#xff0c;是一种网络攻击方式&#xff0c;攻击者通过在受害者浏览器上欺骗或…

【redis】生产级部署

目录 环境部署 redis环境部署 redis多实例配置 构建redis cluster集群 cluster生产集群部署 Cluster集群故障切换 环境部署 1 、关闭防火墙 2 、准备两台虚拟机配置内容如下 redis-master 192.168.108.67 7000 redis-master01 7001 redis-master02 7002 redis-ma…

Vue2.0-3.0 入门到实战 - 初始及插件安装

1 创建view实例,初始化渲染 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body><div id"app">{{ msg }} </div><script type&…

第123天:内网安全-域防火墙入站出站规则不出网隧道上线组策略对象同步

#知识点&#xff1a; 0、防火墙组策略对象 1、OSI七层协议模型 2、正反向监听器说明 3、隧道技术分层协议 4、CS&MSF&控制上线-隧道技术&#xff1a;解决不出网协议上线的问题&#xff08;利用出网协议进行封装出网&#xff09; -代理技术&#xff1a;解决网络通讯不通…

arduino平台控制直流电机PID速度闭环控制编程实现

PID&#xff08;Proportional-Integral-Derivative&#xff0c;比例-积分-微分&#xff09;控制是一种常用的控制算法&#xff0c;可以用于实现直流有刷电机的速度闭环控制。PID控制器根据当前的误差&#xff08;期望速度与实际速度之差&#xff09;来计算输出&#xff0c;以调…

RabbitMQ系列(15)--死信队列的简介与死信队列和死信消费者的实现

1、死信的概念 死信&#xff0c;顾名思义就是无法被消费的消息&#xff0c;一般来说producer&#xff08;生产者&#xff09;将消息投递到broker或直接放到queue&#xff08;队列&#xff09;中&#xff0c;consumer&#xff08;消费者&#xff09;从queue&#xff08;队列&am…

Css基础:盒子模型

1.盒子模型的构成&#xff1a; 边框 外边距 内边距 实际内容 2.table表格的单元格之间的线太粗需要border-collapse:collapse;合并一下边框宽度 3.内边距 padding 4.外边距 margin 块元素水平居中的做法&#xff0c;margin:0 auto; 行内元素和行内块元素 水平居中做…

FreeRTOS ~(五)队列的常规使用 ~ (2/5)队列解决互斥缺陷

前情提要 FreeRTOS ~&#xff08;四&#xff09;同步互斥与通信 ~ &#xff08;2/3&#xff09;互斥的缺陷 举例子说明&#xff1a;利用队列解决前述的"互斥的缺陷"问题 static QueueHandle_t xQueueUARTHandle;/* 利用队列的写数据和读数据来做类似标志位的工作,类…

C++笔记之数组拷贝和vector拷贝

C笔记之数组拷贝和vector拷贝 code review! 文章目录 C笔记之数组拷贝和vector拷贝一.C数组拷贝1.使用循环2.使用std::copy算法3.使用std::array 二.C语言数组拷贝1.使用循环2.使用memcpy函数3.使用for循环和指针 三.CVector拷贝四.公众号&#xff1a;三戒纪元 博文摘抄——C…

Dynamsoft 条形码阅读器 10.0.0 Crack

Dynamsoft 条形码阅读器 10.0.0 将来自不同来源的图像数据转换为标准输入图像数据。 7月 06&#xff0c; 2023 - 10&#xff1a;32新版本 特征 SDK经过重构&#xff0c;与DynamsoftCaptureVision&#xff08;DCV&#xff09;架构集成&#xff0c;该架构包括&#xff1a; ImageS…