03哈希表算法/代码随想录

news2024/12/26 21:22:35

三、哈希表

  1. 有效的字母异位词

    力扣242

    在这里插入图片描述

  • 这题是典型的哈希映射,只要将t存到哈希表中,key为t拆解的值,value为t中有过个key这样的值,然后在使用哈希表O(1)的时间复杂度判断

    class Solution {
        public boolean isAnagram(String s, String t) {
            int[] record = new int[26];
            for (char i: s.toCharArray()) {
                record[i - 'a']++;
            }
    
            for (char i: t.toCharArray()) {
                record[i - 'a']--;
            }
    
            for (int i: record) {
                if (i != 0) {
                    return false;
                }
            }
            return true;
        }
    }
    
  1. 两个数组的交集

    力扣349

    在这里插入图片描述

  • 同样,典型的哈希映射,只要把nums1插接到哈希表中,与上一题相似。然后foreach循环nums2,判断哈希表中是否含有对应值,有的话,就加入返回结果的数组中,注意需要Integer转int

    class Solution {
        public int[] intersection(int[] nums1, int[] nums2) {
            HashMap<Integer, Integer> record = new HashMap<>(1000);
            List<Integer> result = new ArrayList<>();
            for (int i: nums1) {
                record.put(i, record.getOrDefault(i, 0) + 1);
            }
    
            for (int i : nums2) {
                if (record.containsKey(i) && record.get(i) > 0 && !result.contains(i)) {
                    result.add(i);
                }
            }
    
            // 转换 List<Integer> 为 int[]
            int[] intersection = new int[result.size()];
            for (int i = 0; i < result.size(); i++) {
                intersection[i] = result.get(i);
            }
            return intersection;
        }
    }
    
  1. 快乐数

    力扣202

    在这里插入图片描述

  • 看到简单题,我就上了啊,可这,是简单吗,苦命的我啊。这题咋一看很复杂,其实就算很复杂。不开玩笑了,其实题目描述的确实很绕,但其实已经给了结论,给你一个整数,把他每位数拆分并平方算出来的值循环下去,如果中间出现了一开始给的整数,那就不是快乐数,反之就算快乐数。其实是可以证明的,下图所示,再大的数也会不断变小,这里引用力扣官网的说法在这里插入图片描述

  • 最终会得到 1。

  • 最终会进入循环。

  • 值会越来越大,最后接近无穷大。

    对于 3 位数的数字,它不可能大于 243。这意味着它要么被困在 243 以下的循环内,要么跌到 1。4 位或 4 位以上的数字在每一步都会丢失一位,直到降到 3 位为止。所以我们知道,最坏的情况下,算法可能会在 243 以下的所有数字上循环,然后回到它已经到过的一个循环或者回到 1。但它不会无限期地进行下去,所以我们排除第三种选择。

    所以这就是一个不断取个位数并计算然后放入哈希表,看有没有value值会大于1;

    class Solution {
        public boolean isHappy(int n) {
            Set<Integer> result = new HashSet<>();
            while (n != 1 && !result.contains(n)) {
                result.add(n);
                int res = 0;
                while (n > 0) {
                    int i = n % 10;
                    res += i * i;
                    n /= 10;
                }
                n = res;
            }
            return n == 1;
        }
    }
    
  1. 两数之和

    力扣1

    在这里插入图片描述

    太经典了,碰到这种重复的,第一时间就可以想到哈希表,这题需要构建一个哈希表,然后并查找是否含有需要的值。

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

    是这样想的如果直接构建一个哈希表,然后再去计算target-遍历的值,这样是很麻烦的,需要key为nums值,value为统计数,且复杂度会上升。这个时候想到边构建哈希表,边判断是否存在哈希表内,如果元素在哈希表内则返回结果,否则进行构建哈希表,这种双利的方法在后续的题目中也经常用到

  2. 四数相加II

    力扣454

    在这里插入图片描述

    由于是四个数组,不用考虑重复,很简单,两两数组结合构建成哈希表组成所有可能,然后就计算值判断哈希表内存不存在

    class Solution {
        public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
            Map<Integer, Integer> res1 = new HashMap<Integer, Integer>();
            int res = 0;
            int count = 0;
            for (int i = 0; i < nums1.length; ++i) {
                for (int j = 0; j < nums2.length; ++j) {
                    res = nums1[i] + nums2[j];
                    if (res1.containsKey(res)) res1.put(res, res1.get(res) + 1);
                    else res1.put(res, 1);
                }
            }
            for (int i : nums3) {
                for (int j : nums4) {
                    if (res1.containsKey(-i-j)) count += res1.get(-i-j);
                }
            }
            return count;
        }
    }
    

    可以构建两个哈希表,再找值,但这不上繁琐了吗,用到上一题思想,边构建边查,哎,可以再优化,不用构建,直接查,这就形参了上面的写法,写法没有什么难点。

  3. 救赎金

    力扣383

    在这里插入图片描述

    这题其实”有效的字母异位词“很像,都需要构建哈希表,而且结构一样,key为拆开的字符,value为字符出现在字符串的次数。只要先把magazine构建为这样的哈希表,然后ransomNote遍历的时候查询哈希表中有没有这样的值,如果找到了则记得把value减去1,找不到就算是false,注意如果判断哈希表含有ransomNote所需的字符的时候要注意,要判断value,因为value是一个数字,减到0的时候key不会消失是可以查到key的,所以不能单单把key当作判断条件

    class Solution {
        public boolean canConstruct(String ransomNote, String magazine) {
            int[] a = new int[26];
            for (char i :magazine.toCharArray()) {
                a[i - 'a']++;
            }
            for (char i : ransomNote.toCharArray()) {
                a[i - 'a']--;
                if(a[i - 'a'] < 0) {
                    return false;
                }
            }
            return true;
        }
    }
    
  4. 三数之和

    力扣15

    在这里插入图片描述

    这题需要考虑重复,可以想到哈希表,但判断重复的方法比较难想,我先用双指针讲,后面会讲哈希表

    1. 双指针

      class Solution {
          public List<List<Integer>> threeSum(int[] nums) {
      	List<List<Integer>> result = new ArrayList<>();
      	Arrays.sort(nums);
      
      	for (int i = 0; i < nums.length; i++) {
      		// 如果第一个元素大于零,不可能凑成三元组
      		if (nums[i] > 0) {
      			return result;
      		}
      		// 三元组元素a去重
      		if (i > 0 && nums[i] == nums[i - 1]) {
      			continue;
      		}
      
      		HashSet<Integer> set = new HashSet<>();
      		for (int j = i + 1; j < nums.length; j++) {
      			// 三元组元素b去重
      			if (j > i + 2 && nums[j] == nums[j - 1] && nums[j - 1] == nums[j - 2]) {
      				continue;
      			}
      
      			int c = -nums[i] - nums[j];
      			if (set.contains(c)) {
      				result.add(Arrays.asList(nums[i], nums[j], c));
      				set.remove(c); // 三元组元素c去重
      			} else {
      				set.add(nums[j]);
      			}
      		}
      	}
      	return result;
          }
      }
      

      首选排序,(为什么排序呢,如果不排序重复的元素不靠在一起就不好处理,下面同理)选取a作为最外层循环,b作为left指针,c作为right指针,a开始遍历整个数组,b从a迭代开始的元素开始,c始终为最后一个元素,在a的每一层循环,判断时,只要保持left<right,就可以继续判断。从上面的描述就是代码的主流程,不同于暴力三层循环,我才用a为外层循环,bc指针作为左右指针,不断逼近,可以把每一种条件都算在内,而且始终不和a接触,这样可以始终保持不重复,因为a是不断往前的,往前的过程中b和c只能在a的更前面,这就保证了不会重复。但是到这里有问题。如果每个都不一样,则已经完成,但可能存在元素相同,a是主循环,每一此值不能一样,要不然得出的结果必定重复,a的去重完成。如果b确定,c就确定,因为a已经确定了,所以当b重复的时候,要直接删除,c也同理。而且b必须和前一个元素比,c必须和后一个比,要不然[-1, -1, 0, 1, ,1],b刚到-1就结束了

    2. 哈希

      class Solution {
          public List<List<Integer>> threeSum(int[] nums) {
      	List<List<Integer>> result = new ArrayList<>();
      	Arrays.sort(nums);
      
      	for (int i = 0; i < nums.length; i++) {
      		// 如果第一个元素大于零,不可能凑成三元组
      		if (nums[i] > 0) {
      			return result;
      		}
      		// 三元组元素a去重
      		if (i > 0 && nums[i] == nums[i - 1]) {
      			continue;
      		}
      
      		HashSet<Integer> set = new HashSet<>();
      		for (int j = i + 1; j < nums.length; j++) {
      			// 三元组元素b去重
      			if (j > i + 2 && nums[j] == nums[j - 1] && nums[j - 1] == nums[j - 2]) {
      				continue;
      			}
      
      			int c = -nums[i] - nums[j];
      			if (set.contains(c)) {
      				result.add(Arrays.asList(nums[i], nums[j], c));
      				set.remove(c); // 三元组元素c去重
      			} else {
      				set.add(nums[j]);
      			}
      		}
      	}
      	return result;
          }
      }
      

      这里的哈希不太好理解,这里也用到了和两数之和我说的那种哈希表构建方法,“边判断边构建”,涉及到这种需要大量哈希表计算的时候,这种思想很剩时间以及空间。难度就算在去重,其实也是选取a为外层循环,通过计算然后构建哈希表,判断是否有存在对应的key。同理双指针法,先排序,a不能重复,重复得到的值也是一样的,所以去重a不能重复,然后开始遍历b就算a的索引+1,这个时候用到两数之和的思想,先抛开,三数之和,这里就是两数之和,我先得到需要的target,就是-a,然后知道b了,target为-a-b,这个时候构建哈希表,没有就存,有就返回。然后就是去重了,a以及完毕了,我们知道,如果知道abc之中任意两个,其他一个就确定了,所以当c找到哈希表有对应的值后,需要把哈希表的那个键值对直接删除,以避免重复。去重b,为什么去重b,肯定是有对应场景,正常全不相等的场景不需要去重,只要重复的地方才需要,[-1, -1, -1, 0, 0] [-1, -1, 0, 1]这里只有前面的情况需要去重,因为是三数,允许两个相同的元素存在,但如果用不到则不能重复添加,所以这使用的hash集合,可直接去重复。所以重复数字达到三次才需要在条件判断的时候就删除,要这么写j > i + 2 && nums[j] == nums[j - 1] && nums[j - 1] == nums[j - 2]

  5. 四数之和

    力扣18

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    和三数之和区别不大,只是外层循环变为两层,可以适当剪枝,就算加if判断提前结束

    class Solution {
        public List<List<Integer>> fourSum(int[] nums, int target) {
            Arrays.sort(nums);
            List<List<Integer>> result = new ArrayList<>();
            
            if (nums.length < 4) {
                return result;
            }
            if (nums[0] > Integer.MAX_VALUE) {
                return result;
            } 
    
            for (int i = 0; i < nums.length - 3; ++i) {
                if (i > 0 && nums[i] == nums[i - 1]) {
                    continue; // 去重
                }
                for (int j = i + 1; j < nums.length - 2; ++j) {
                    if (j > i + 1 && nums[j] == nums[j - 1]) {
                        continue; // 去重
                    }
                    int left = j + 1;
                    int right = nums.length - 1;
                    while (left < right) {
                        long sum = (long)nums[i] + nums[j] + nums[left] + nums[right];
                        if (sum > target) {
                            right--;
                        } else if (sum < target) {
                            left++;
                        } else {
                            result.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
                            while (left < right && nums[left] == nums[left + 1]) left++; // 去重
                            while (left < right && nums[right] == nums[right - 1]) right--; // 修正
    
                            left++;
                            right--;
                        }
                    }
                }
            }
            return result;
        }
    }
    

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

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

相关文章

下载安装COPT+如何在jupyter中使用(安装心得,windows,最新7.2版本)

目录 1.到杉树科技官网申请下载COPT 2.安装COPT&配置许可文件 3.在jupyter中使用COPT的python接口 最近看到一本和数学建模有关的新书&#xff1a;《数学建模与数学规划&#xff1a;方法、案例及编程实战》&#xff0c;作为数学建模老手&#xff0c;肯定要学习一下&…

【Linux】——操作系统-进程详解

大家好呀&#xff0c;我是残念&#xff0c;希望在你看完之后&#xff0c;能对你有所帮助&#xff0c;有什么不足请指正&#xff01;共同学习交流哦 本文由&#xff1a;残念ing原创CSDN首发&#xff0c;如需要转载请通知 个人主页&#xff1a;残念ing-CSDN博客&#xff0c;欢迎各…

Excel:vba实现批量插入图片批注

实现的效果&#xff1a;实现的代码如下&#xff1a; Sub InsertImageNamesAndPictures()Dim PicPath As StringDim PicName As StringDim PicFullPath As StringDim RowNum As IntegerDim Name As StringDim Comment As CommentDim folder As FileDialog 定义文件选择对话框 清…

HTML 语法规范——代码注释、缩进与格式、标签与属性、字符编码等

文章目录 一、代码注释1.1 使用注释的主要目的1.2 使用建议二、标签的使用2.1 开始标签和结束标签2.2 自闭合标签2.3 标签的嵌套2.4 标签的有效性三、属性四、缩进与格式4.1 一致的缩进4.2 元素单独占用一行4.3 嵌套元素的缩进4.4 避免冗长的行五、字符编码六、小结在开发 HTML…

闯关leetcode——242. Valid Anagram

大纲 题目地址内容 解题代码地址 题目 地址 https://leetcode.com/problems/valid-anagram/ 内容 Given two strings s and t, return true if t is an anagram of s, and false otherwise. Example 1: Input:s “anagram”, t “nagaram” Output:true Example 2: Inp…

无人机之远程指挥中心技术篇

一、核心功能 实时监控与控制&#xff1a; 通过高清视频流和其他传感器数据&#xff0c;指挥中心可以实时了解无人机的当前状态、位置和环境情况。操作人员可以在指挥中心对无人机进行精确的飞行控制&#xff0c;包括起飞、降落、悬停、移动等&#xff0c;确保无人机按照预定…

C++学习路线(数据库部分)二

类型 整形类型 整数类型是数据库中最基本的数据类型。标准SQL中支持INTEGER和SMALLINT这两种数据类型。MySQL数据库除了支持这两种类型以外&#xff0c;还扩展支持了TINYINT、MEDIUMINT和BIGINT。下表从不同整数类型的字节数、取值范围等方面进行对比。 类型名称后面的小括号…

秒杀优化(异步秒杀,基于redis-stream实现消息队列)

目录 秒杀优化一&#xff1a;异步秒杀1&#xff1a;思路2&#xff1a;实现 二&#xff1a;redis实现消息队列1&#xff1a;什么是消息队列2&#xff1a;基于list结构实现消息队列3&#xff1a;基于pubsub实现消息队列4&#xff1a;基于stream实现消息队列5&#xff1a;stream的…

机器视觉基础—双目相机

机器视觉基础—双目相机与立体视觉 双目相机概念与测量原理 我们多视几何的基础就在于是需要不同的相机拍摄的同一个物体的视场是由重合的区域的。通过下面的这种几何模型的目的是要得到估计物体的长度&#xff0c;或者说是离这个相机的距离。&#xff08;深度信息&#xff09…

Java使用apache.commons.io框架下的FileUtils类实现文件的写入、读取、复制、删除

Apache Commons IO 是 Apache 开源基金组织提供的一组有关IO&#xff08;Input/Output&#xff09;操作的小框架&#xff0c;它是 Apache Commons 项目的一部分&#xff0c;专注于提供简单易用的 API&#xff0c;用于处理输入和输出操作。Apache Commons IO 是一个功能强大的 J…

【论文解读】EdgeYOLO:一种边缘实时目标检测器(附论文地址)

论文地址&#xff1a;https://arxiv.org/pdf/2302.07483 这篇文章的标题是《EdgeYOLO: An Edge-Real-Time Object Detector》&#xff0c;由中国北京理工大学的Shihan Liu、Junlin Zha、Jian Sun、Zhuo Li和Gang Wang共同撰写。这篇论文提出了一个基于最新YOLO框架的高效、低复…

Redis 位图实现签到之长时间未签到预警

#目前通行系统项目中有一个新需求【通过对通行记录数据定时分析&#xff0c;查询出长时间没 有刷卡/刷脸通行的学生】 #一看到通行签到相关&#xff0c;就想到了redis的位图&#xff0c;理由也有很多帖子说明了&#xff0c;最大优点占用空间小。 一.redis命令行 SETBIT&#…

【Git】从 GitHub 仓库中移除误提交的 IntelliJ IDEA 配置文件夹 .idea 并将其添加到 .gitignore 文件中

问题描述 在使用Git进行版本控制时&#xff0c;不慎将.idea文件夹提交至GitHub仓库&#xff0c;即使后续在.gitignore文件中添加了.idea&#xff0c;但该文件夹仍在仓库中存在。 原因分析 .idea 是 IntelliJ IDEA 开发工具为项目创建的一个配置文件夹。IntelliJ IDEA 是一个广…

[Linux] 进程地址空间

&#x1fa90;&#x1fa90;&#x1fa90;欢迎来到程序员餐厅&#x1f4ab;&#x1f4ab;&#x1f4ab; 主厨&#xff1a;邪王真眼 主厨的主页&#xff1a;Chef‘s blog 所属专栏&#xff1a;青果大战linux 总有光环在陨落&#xff0c;总有新星在闪烁 好了&#xff0c;折腾…

Vue3 + Element Plus简单使用案例及【eslint】报错处理

本电脑Vue环境已安装正常使用 博主使用npm 包管理器安装 Element Plus.有问题评论区帮忙指正,感谢阅读. 在完成的过程中如果遇到eslint报错 Parsing error &#xff1a;Unexpected token { eslint 这个报错&#xff0c;也可以尝试第7部分报错处理解决。 目录 1.新建项目 2…

【云原生】Docker搭建开源翻译组件Deepl使用详解

目录 一、前言 二、微服务项目使用翻译组件的场景 2.1 多语言用户界面 2.2 业务逻辑中的翻译需求 2.3 满足实时通信的要求 2.4 内容管理系统 2.5 个性化推荐系统 2.6 日志和监控 三、开源类翻译组件解决方案 3.1 国内翻译组件方案汇总 3.1.1 百度翻译 3.1.2 腾讯翻…

DFA算法实现敏感词过滤

DFA算法实现敏感词过滤 需求&#xff1a;检测一段文本中是否含有敏感词。 比如检测一段文本中是否含有&#xff1a;“滚蛋”&#xff0c;“滚蛋吧你”&#xff0c;“有病”&#xff0c; 可使用的方法有&#xff1a; 遍历敏感词&#xff0c;判断文本中是否含有这个敏感词。 …

如何在Linux系统中使用Netcat进行网络调试

文章目录 Netcat简介安装Netcat在Debian/Ubuntu系统中安装在CentOS/RHEL系统中安装 Netcat基本命令Netcat基本用法示例1&#xff1a;监听端口示例2&#xff1a;连接到远程主机 Netcat选项-l选项-p选项-v选项 Netcat模式监听模式连接模式 Netcat排除和包含排除端口包含端口 Netc…

【ClickHouse 探秘】你知道 ClickHouse MergeTree 引擎吗?

&#x1f449;博主介绍&#xff1a; 博主从事应用安全和大数据领域&#xff0c;有8年研发经验&#xff0c;5年面试官经验&#xff0c;Java技术专家&#xff0c;WEB架构师&#xff0c;阿里云专家博主&#xff0c;华为云云享专家&#xff0c;51CTO 专家博主 ⛪️ 个人社区&#x…

推荐一款高效的内存清理工具:MemoryCleaner

MemoryCleaner是一款高效的内存清理工具&#xff0c;旨在优化您的计算机性能。它利用Windows内置的多种功能&#xff0c;能够在不影响系统运行的情况下&#xff0c;自动释放内存。用户可以通过系统托盘直接访问MemoryCleaner的功能&#xff0c;无需打开程序&#xff0c;使得内存…