C++算法训练营 Day6 哈希表(1)

article/2025/6/9 19:56:01

1.有效的字母异位词

  • LeetCode:242.有效的字母异位词

给定两个字符串st ,编写一个函数来判断t是否是s的字母异位词。

示例 1:

输入: s = “anagram”, t = “nagaram”
输出: true

示例 2:

输入: s = “rat”, t = “car”
输出: false

  • 解题思路:

由题可知,字母异位词是两个数组字母相同但是顺序不同,我们需要快速的找出某个值是否在表中,因此考虑使用哈希表。

1.使用一个大小为26的数组(对应26个英文字母)作为计数器;
2.遍历第一个字符串,将出现的字母对应增加相应字符的计数;
3.遍历第二个字符串,将出现的字母减少相应字符的计数;
4.如果两个字符串是字母异位词,最终计数器所有位置都应为0

其中创建一个包含26个整数的数组(初始化为0),每个位置对应一个字母,如:

res[0] → ‘a’ 的计数
res[1] → ‘b’ 的计数

res[25] → ‘z’ 的计数

然后将字符到索引利用一个巧妙的ASCII码进行转换s[i] - 'a',如:

‘a’ 的ASCII码是97
‘b’ 是98,
…,
‘z’ 是122

然后通过计算可得:

‘a’ - ‘a’ = 0
‘b’ - ‘a’ = 1

‘z’ - ‘a’ = 25

从而就得到了每个字母的对应位置。由此便可进行计算

如:
(1)有效字母异位词

s = “anagram”, t = “nagaram”

1.遍历s: a→+1, n→+1, a→+1, g→+1, r→+1, a→+1, m→+1
2.遍历t: n→-1, a→-1, g→-1,a→-1, r→-1, a→-1, m→-1
3.所有计数器归零 → 返回true

(2)无效字母异位词

s = “rat”, t = “car”

1.遍历s: r→+1, a→+1, t→+1
2.遍历t: c→-1, a→-1, r→-1
3.最终计数器中: a:0, r:0, t:+1,c:-1
t,c是非零值 ,因此返回false

class Solution {
public:bool isAnagram(string s, string t) {//步骤1:创建计数器数组int res[26] = {0};//步骤2:遍历字符串s,增加字符计数for(int i = 0; i < s.size(); ++i) res[s[i] - 'a']++;//步骤3:遍历字符串t,减少字符计数for(int i = 0; i < t.size(); ++i) res[t[i] - 'a']--;//步骤4:检查计数器是否全为0for(int i = 0; i < 26; ++i) {if(res[i] != 0) return false;  //任何非零值都表示计数不匹配}return true;  //所有计数均为0,是字母异位词}
};

2.两个数组的交集

  • LeetCode:349.两个数组的交集

给定两个数组nums1nums2,返回它们的交集 。输出结果中的每个元素一定是唯一的。我们可以不考虑输出结果的顺序 。

示例 1:

输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]

示例 2:

输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4]
解释:[4,9] 也是可通过的

  • 解题思路:

本题要求我们找出两个数组中的相同元素,涉及到快速查找某个元素是否在表中,因此考虑用哈希表来求解,此外若题目限制了数组的大小可以选择数组来解题,但是本道题没有规定数组的大小,因此无法用数组来做哈希表,而且如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费。因此我们考虑使用set或map,对于本题来说,我们只需返回相同的元素即可,且不要求顺序,因此我们使用unordered_set求解。

首先unordered_set中数值要求不能重复,因此会自动过滤重复元素,我们可以创建一个结果集用来存放交集元素,同时将数组nums1转换为哈希表,即:

[1,2,2,1] → {1,2}

具体操作为:

  	unordered_set<int> result_set; //存储结果的集合(自动去重)unordered_set<int> nums_set(nums1.begin(), nums1.end()); //将nums1转换为哈希集合(自动去重)

然后我们遍历nums2,同时在哈希表nums1中寻找nums2中有的元素,若找着了,就把这个元素插入到结果集中即:

for (int num : nums2) {//检查当前元素是否存在于nums1的集合中if (nums_set.find(num) != nums_set.end()) {result_set.insert(num);  //存在则加入结果集}}

对于int num:是声明了一个临时变量num,类型是int,每次循环时,num会被自动赋值为nums2的当前元素。注意:这里是值拷贝,即复制元素值nums2:则是要遍历的容器,这里是vector。编译器会自动处理迭代过程。即执行流程为:

第一次循环:num = nums2的第一个元素
第二次循环:num = nums2的第二个元素

直到遍历完nums2中所有元素

if (nums_set.find(num) != nums_set.end())是判断元素num是否存在于集合nums_set中的标准方法。

nums_set.find(num):在集合中查找键为num的元素

若找到:返回指向该元素的迭代器
若未找到:返回一个特殊的迭代器nums_set.end()(表示集合末尾的下一个位置,为无效位置)

最后将结果集转化为vector返回,即:

  return vector<int>(result_set.begin(), result_set.end());

整体C++代码为:

vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {//存储结果的集合(自动去重)unordered_set<int> result_set; //将nums1转换为哈希集合(自动去重)unordered_set<int> nums_set(nums1.begin(), nums1.end());//遍历nums2中的每个元素for (int num : nums2) {//检查当前元素是否存在于nums1的集合中if (nums_set.find(num) != nums_set.end()) {result_set.insert(num);  //存在则加入结果集}}//将结果集合转换为vector返回return vector<int>(result_set.begin(), result_set.end());
}

3.快乐数

  • LeetCode:202.快乐数

编写一个算法来判断一个数 n 是不是快乐数。「快乐数」 定义为:

对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为1,也可能是无限循环但始终变不到1
如果这个过程 结果为1,那么这个数就是快乐数。
如果n快乐数就返回true;不是,则返回false

示例 1:

在这里插入图片描述

示例 2:

在这里插入图片描述

-解题思路:

由题意,对于一个正整数,重复将其替换为各位数字的平方和,最终结果变为1的数即为快乐数。而无限循环时不是快乐数,而在无限循环的过程中,一定会出现重复的结果,因此我们需要在结果集中快速寻找是否存在重复的结果,若存在即陷入循环了,就不是循环数。此外对结果的顺序不做要求,因此选择unordered_set。

首先,我们需要计算给定n的各位平方和,即:

 //计算数字各位平方和的辅助函数int getsum(int n) {int sum = 0;while(n) {  //当n不为0时继续处理sum += (n % 10) * (n % 10);  //取最后一位数字并平方n /= 10;  //移除最后一位数字}return sum;}

这是一个基本的处理一个整数各个位的方法,如:

初始:n=19
第一次循环:19 % 10 = 9, 则sum = 81, 19 / 10 = 1,即n更新为1
第二次循环:1 % 10 = 1, sum = 81 + 1 = 82, 1 / 10 = 0
不满足循环条件,返回82

然后,我们需要创建一个结果集,用来存放所有sum。并使用哈希集合检测循环,若结果等于1,则说明为快乐数;若结果重复出现,则说明非快乐数。

  unordered_set<int> res;  // 储出现过的计算结果while(1) {  //无限循环直到找到结果int sum = getsum(n);  //计算当前数字的平方和//检查是否满足快乐数条件if(sum == 1) return true;  //检查是否出现循环(结果重复)if(res.find(sum) != res.end()) return false;else res.insert(sum);  //记录新结果n = sum;  //更新n为新的计算结果,确保每次迭代使用最新计算结果}

整体代码为:

class Solution {
public:int getsum(int n) {int sum = 0;while(n) {  //当n不为0时继续处理sum += (n % 10) * (n % 10);  //取最后一位数字并平方n /= 10;  //移除最后一位数字}return sum;}//判断是否为快乐数bool isHappy(int n) {unordered_set<int> res;  //存储出现过的计算结果while(1) {  // 无限循环直到找到结果int sum = getsum(n);  //计算当前数字的平方和//检查是否满足快乐数条件if(sum == 1) return true;  //检查是否出现循环(结果重复)if(res.find(sum) != res.end()) return false;else res.insert(sum);  //记录新结果n = sum;  //更新n为新的计算结果}}
};

4.两数之和

  • LeetCode:1.两数之和

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

你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]

示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]

  • 解题思路

本题不是直接找两个数,而是对于每个元素nums[i],检查target - nums[i]是否存在于之前遍历过的元素中,其思路与有效字母异位词的思路一致。即如果a + b = target
那么b = target - a。因此我们可以使用哈希表:使用unordered_map存储已遍历元素的值和索引,通过一次遍历,边遍历边检查边存储。

首先建立结果集:

unordered_map<int,int> res//键:元素值,值:元素索引

key用来存储数组元素的值,用于快速查找;value用来存储该元素的索引,用于最终返回结果。

然后通过遍历结果集查找是否存在target - a,若存在返回下标,若不存在返回空。即整体流程为:

假设我们输入:

nums = [2, 7, 11, 15], target = 9

执行流程:

第一次循环:i=0,nums[0]=2
结果集中查找9-2=7(不存在)
插入map: {2:0}
第二次循环: i=1,nums[1]=7
结果集中查找9-7=2(找到,索引为0)
返回[0,1]

for(int i = 0; i < nums.size(); i++) {// 尝试寻找能与nums[i]配对的数auto iter = map.find(target - nums[i]);// 如果找到配对if(iter != map.end()) {return {iter->second, i};  // 返回两个索引}// 将当前元素存入map(先检查后存储,避免自匹配)map.insert(pair<int, int>(nums[i], i)); }
return { };

整体代码为:

vector<int> twoSum(vector<int>& nums, int target) {std::unordered_map<int,int> res;  //键:元素值,值:元素索引for(int i = 0; i < nums.size(); i++) {//尝试寻找能与nums[i]配对的数auto it = res.find(target - nums[i]);//如果找到配对if(it != res.end()) {return {it->second, i};  //返回两个索引}  //将当前元素存入map(先检查后存储,避免自匹配)res.insert(pair<int, int>(nums[i], i)); }return {};  
}

pair<int, int>pair为是C++标准库中的模板类,用于存储两个值作为一个单元。这里相当于创建了一个临时对象,包含:first = nums[i]second = i。当插入元素时,必须同时提供keyvalue,而pair正好把这两个值打包成一个对象。


http://www.hkcw.cn/article/rmDFZjrTEJ.shtml

相关文章

LeetCode hot100-11

题目描述 题目链接&#xff1a;滑动窗口最大值 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例 1&#xff1a; 输入…

js web api阶段

一.变量声明 1.JS中的const const在js修饰数组和对象&#xff0c;本质类似与c的引用数据类型&#xff0c;所以类似于 int* const ref 修饰的是地址&#xff0c;值是可以改变的 然后下面这种情况是禁止的 左边这种都有括号&#xff0c;说明是建立了一个块新地址去存放&#xf…

【计算机网络】数据链路层——ARP协议

&#x1f525;个人主页&#x1f525;&#xff1a;孤寂大仙V &#x1f308;收录专栏&#x1f308;&#xff1a;计算机网络 &#x1f339;往期回顾&#x1f339;&#xff1a;【计算机网络】网络层IP协议与子网划分详解&#xff1a;从主机通信到网络设计的底层逻辑 &#x1f516;流…

群晖 NAS 如何帮助培训学校解决文件管理难题

在现代教育环境中&#xff0c;数据管理和协同办公的效率直接影响到教学质量和工作流畅性。某培训学校通过引入群晖 NAS&#xff0c;显著提升了部门的协同办公效率。借助群晖的在线协作、自动备份和快照功能&#xff0c;该校不仅解决了数据散乱和丢失的问题&#xff0c;还大幅节…

基于LLaMA-Factory和Easy Dataset的Qwen3微调实战:从数据准备到LoRA微调推理评估的全流程指南

随着开源大模型如 LLaMA、Qwen 和 Baichuan 的广泛应用&#xff0c;其基于通用数据的训练方式在特定下游任务和垂直领域中的表现仍存在提升空间&#xff0c;因此衍生出针对具体场景的微调训练需求。这些训练涵盖预训练&#xff08;PT&#xff09;、指令微调&#xff08;SFT&…

视觉语言动作模型 (VLAs) :赋予机器行动的智慧

文章目录 一、VLA 的诞生&#xff1a;从单模态到多模态的飞跃二、深入剖析 VLA&#xff1a;核心组件与工作原理三、前沿进展&#xff1a;那些令人瞩目的 VLA 模型与趋势四、VLA 的广阔天地&#xff1a;应用场景一览五、挑战与荆棘&#xff1a;VLA 面临的难题六、未来展望&#…

C/S医学影像系统源码,全院一体化PACS系统源码,实现全院检查预约和信息共享互通

全院一体化PACS系统源码 全院级PACS系统不仅仅具有安全、高效、稳定的访问/存储/调阅架构和强大的影像后台处理功能&#xff1b;还是一个全院一体化的PACS系统&#xff0c;覆盖了医院所有影像科室&#xff08;放射、超声、内镜、病理、心脑电等&#xff09;&#xff1b;从影像…

力扣刷题Day 69:搜索二维矩阵(74)

1.题目描述 2.思路 首先判断target是否有可能在矩阵的某一行里&#xff0c;没可能直接返回False&#xff0c;有可能就在这一行里二分查找。 3.代码&#xff08;Python3&#xff09; class Solution:def searchMatrix(self, matrix: List[List[int]], target: int) -> boo…

生成JavaDoc文档

生成 JavaDoc 文档 1、快速生成 文档 注解 2、常见的文档注解 3、脚本生成 doc 文档 4、IDEA工具栏生成 doc 文档 第一章 快速入门 第01节 使用插件 在插件工具当中&#xff0c;找到插件 javaDoc 使用方式&#xff0c;在代码区域&#xff0c;直接点击右键。选择 第02节 常用注…

攻防世界RE-1000Click

首先按一千次肯定是不可能的&#xff0c;观察到验证flag时会有一个输出&#xff1a; 直接在ida中搜索这个错误提示词&#xff1a; 往上找找就能找到flag&#xff1a; flag: flag{TIBntXVbdZ4Z9VRtoOQ2wRlvDNIjQ8Ra}

【嵌入式(2)深入剖析嵌入式开发:从基础到实战】

为打造符合CSDN高质量博文标准的内容&#xff0c;我以清晰目录架构梳理知识&#xff0c;插入代码示例、时序图等增强可读性&#xff0c;并添加投票互动&#xff0c;提升文章吸引力与互动性。 目录 [引言一、嵌入式处理器的分类及特点二、硬件、软件与固件&#xff1a;嵌入式系…

数据库-联合查询(内连接外连接),子查询,合并查询

一.为什么要使用联合查询 在数据设计时由于范式的要求&#xff0c;数据被拆分到多个表中&#xff0c;那么要查询一个条数据的完整信息&#xff0c;就要从多个表中获取数据&#xff0c;如下图所示&#xff1a;要获取学生的基本信息和班级信息就要从学生表和班级表中获取&#xf…

dvwa6——Insecure CAPTCHA

captcha&#xff1a;大概是“我不是机器人”的一个勾选框或者图片验证 LOW: 先输入密码正常修改试一下&#xff08;123&#xff09;&#xff0c;发现报错 查看源码&#xff1a; <?phpif( isset( $_POST[ Change ] ) && ( $_POST[ step ] 1 ) ) {// Hide the C…

通过基于流视频预测的可泛化双手操作基础策略

25年5月来自中国电信、西北工业大学和香港科大的论文“Towards a Generalizable Bimanual Foundation Policy via Flow-based Video Prediction”。 由于动作空间巨大且需要协调手臂运动&#xff0c;学习可泛化的双手操作策略对于具身智体而言极具挑战性。现有方法依赖于视觉-…

隧道监测预警系统:构筑智慧交通的安全中枢

在交通基础设施体系中&#xff0c;隧道作为关键节点&#xff0c;其安全运营直接关系到整个路网的畅通与稳定。隧道监测预警系统通过多维度感知网络与智能分析中枢的有机融合&#xff0c;构建起全天候、立体化的安全防护体系&#xff0c;成为守护隧道安全的智能防线。 一、系统…

【相机基础知识与物体检测】更新中

参考&#xff1a; 黑马机器人 | 相机标定&物体检测https://robot.czxy.com/docs/camera/ 01-相机基础 相机基础概述 相机是机器视觉的基础&#xff0c;相机直接产生了相机数据。所有视觉算法都是作用在相机数据上的。相机数据的好坏&#xff0c;或者对相机数据的理解方式…

Nginx实战

更多推荐阅读&#xff1a; 前端性能&异常分析排查流程-CSDN博客 关于列表性能分析与标准-CSDN博客 Fullcalendar常用功能介绍-CSDN博客 目录 Nginx介绍 下载和安装 实战分享 场景一、localhost代理线上环境 场景二&#xff1a;通过本地路径访问其他域名的地址信息 防盗链功…

java实用类

文章目录 SystemSystem.exit(int status);currentTimeMillis String 类String两种创建方式String提供的常用方法 Runtime作用演示 Object类常用方法重写 toString()重写 equals() 和 hashCode() BigInter类BigInter 构造方法常用方法演示 BigDecimal类常见构造器常用方法演示 S…

windows安装多个版本composer

一、需求场景 公司存在多个项目&#xff0c;有的项目比较老&#xff0c;需要composer 1.X版本才能使用 新的项目又需要composer 2.X版本才能使用 所以需要同时安装多个版本的composer二、下载多个版本composer #composer官网 https://getcomposer.org/download/三、放到指定目…

【域控制器EMC】域控制器EMC设计总结

一&#xff1a;总结 汇总项目设计当中关于EMC的设计要点&#xff0c;主要从原理设计、Layout、结构、外设部分总结。 满足要求的器件和合理的电路能降低电磁干扰&#xff1b; 正确的布局、接地、信号路径、屏蔽等可以减少电磁辐射。 结构件设计也会对EMC性能产生影响 二&a…