代码随想录笔记|C++数据结构与算法学习笔记-哈希表(一)|有效的字母异位词、两个数组的交集、快乐数、两数之和、四数相加II

文章目录

  • 242.有效的字母异位词
    • 哈希法解法
      • 解题思路
      • 伪代码
      • c++代码
  • 349.两个数组的交集
    • set解决
      • 伪代码
      • c++代码
    • 数组解决
  • 202.快乐数
    • 思路
    • 伪代码讲解
    • C++代码
  • 1.两数之和
    • 思路
    • map解题过程
    • 伪代码
    • C++代码
  • 454.四数相加II
    • 整体思路
    • map解题过程
    • 注意事项
    • 伪代码
    • C++代码

《代码随想录链接》

本文基于代码随想录,写入一些自己的想法。

242.有效的字母异位词

力扣题目链接

哈希表最擅长解决的问题就是:给你一个元素,判断在这个集合里是否出现过。只要遇到类似场景,那么我们就很可能用哈希表。

这段话可以反复咀嚼,从每个哈希法的题目中理解。

哈希法解法

一般对于哈希法的思路,我们需要用到以下三种数据结构:

  • 数组
  • set集合
  • map映射

对于元素个数比较少,我们可以使用数组

如果元素个数过多,我们可以使用set集合

如果元素稀疏,那么就选用map(例如0 5 1000000)

解题思路

如果定义一个数组hash[26],这个数组来记录各个字母出现的次数。对于第一个字符串,我们将其记录进数组,也就是数组各个元素+1,对于第二个字符串,我们通过各个元素-1来记录。那么如果st每个字符出现次数相同,那么数组中每个元素都应该为0,否则,里面就是出现某个元素是非零的情况

伪代码

int hash[26];
for (i = 0; i < s.size; i++)
{hash[s[i]-'a']++;		//典型的哈希操作,我们不需要知道字母a的ASCII码是多少,只需要把它对应的减下去,那0就对应a
}
for (j = o, j < t.size; j++)
{hash[t[i]-'a']--;
}
for (i = 0; i < 26;i++)if (hash[i] != 0 )	return false;

c++代码

class Solution {
public:bool isAnagram(string s, string t) {int record[26] = {0};for (int i = 0; i < s.size(); i++) {// 并不需要记住字符a的ASCII,只要求出一个相对数值就可以了record[s[i] - 'a']++;}for (int i = 0; i < t.size(); i++) {record[t[i] - 'a']--;}for (int i = 0; i < 26; i++) {if (record[i] != 0) {// record数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。return false;}}// record数组所有元素都为零0,说明字符串s和t是字母异位词return true;}
};

349.两个数组的交集

力扣题目链接

哈希表最擅长解决的问题就是:给你一个元素,判断在这个集合里是否出现过。只要遇到类似场景,那么我们就很可能用哈希表。

set解决

如果用上面的逻辑我们就很好理解这道题了:

  • 构造一个哈希表:对于nums1我们要把他进行处理,转换成哈希表;

  • 给你一个元素,判断在这个集合里是否出现过:然后我们拿nums2的元素去判断在哈希表的集合里是否出现过。如果出现过,我们就讲该元素存入result

这里小小记录一下几个不同的set

  • setmulti_set 底层实现都是红黑树
  • unordered_set. 底层实现是哈希值直接映射,可以理解为一个无限存装的数组。

上述三个具体如何选择呢?《代码随想录》

本题中我们选择unordered_set,因为它在做映射的过程中效率最高,取值操作效率也是最高的。因为另外两个的底层是树,取值的时候还有一个查找的过程

伪代码

unorder_set result;	//由于题目中要求去重,不如直接设置一个set变量,他会自动去重
unorder_set num_set(nums1);
for (i = 0; i < nums2.size; i++)if(nums_set.find(nums2[i]) != nums_set.end())		//如果找到了该元素result.insert(nums2[i]);
return vector(result);

c++代码

class Solution {
public:vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {unordered_set<int> result_set; // 存放结果,之所以用set是为了给结果集去重unordered_set<int> nums_set(nums1.begin(), nums1.end());for (int num : nums2) {// 发现nums2的元素 在nums_set里又出现过if (nums_set.find(num) != nums_set.end()) {result_set.insert(num);}}return vector<int>(result_set.begin(), result_set.end());}
};

数组解决

其实就是用数组来构造哈希表

class Solution {
public:vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {unordered_set<int> result_set; // 存放结果,之所以用set是为了给结果集去重int hash[1005] = {0}; // 默认数值为0for (int num : nums1) { // nums1中出现的字母在hash数组中做记录hash[num] = 1;}for (int num : nums2) { // nums2中出现话,result记录if (hash[num] == 1) {result_set.insert(num);}}return vector<int>(result_set.begin(), result_set.end());}
};

202.快乐数

力扣题目链接

题目中对快乐数的描述说会 无限循环,那么也就是说求和的过程中,sum会重复出现,这对解题很重要!

然后再次印证上文说的思想,给你一个元素,判断在这个集合里是否出现过。只要遇到类似场景,那么我们就很可能用哈希表

所以这道题目使用哈希法,来判断这个sum是否重复出现,如果重复了就是return false, 否则一直找到sum为1为止。

判断sum是否重复出现就可以使用unordered_set。

思路

现在难点就是两个

  • 发现求和过程中,无限循环的含义,因为是循环,就表示sum重复出现,所以我们需要用哈希
  • 求和的过程,对取数值各个位上的单数操作要熟悉
//取各个位上的单数平方之和
int getSum(int n)
{int sum = 0;while (n){sum += (n % 10) * (n % 10);n /= 10;}return sum;
}

伪代码讲解

unordered_set<int> set;
while(1)	//先主动构造一个死循环,如果找到了1我们就跳出循环,如果sum开始重复,那么立即跳出
{if sum = getSum(n);		//各个位数平方求和//找到1跳出循环if (sum == 1)	return true;	//sum开始重复,进入了死循环。没有重复的话,我们把sum先存入setif (set.find(sum) != set.end()) return false;else set.insert(sum);	//把新sum赋给n,开始下一次循环n = sum;
}

C++代码

class Solution {
public:// 取数值各个位上的单数之和int getSum(int n) {int sum = 0;while (n) {sum += (n % 10) * (n % 10);n /= 10;}return sum;}bool isHappy(int n) {unordered_set<int> set;while(1) {int sum = getSum(n);if (sum == 1) {return true;}// 如果这个sum曾经出现过,说明已经陷入了无限循环了,立刻return falseif (set.find(sum) != set.end()) {return false;} else {set.insert(sum);}n = sum;}}
};

1.两数之和

力扣题目链接

四个重点,请看完解析之后进行回答:

  • 为什么想到用哈希表
  • 为什么要用map,为什么要用unordered_map
  • map究竟是来做什么的,这取决于我们写代码的思路
  • map中的key和value分别用来存放什么,为什么?

思路

那么本题我们为什么会想到用哈希法呢?

我们用什么样的哈希表来存这个结构呢?

  • 因为我们在遍历原数组的元素时,我们要存放我们之前遍历的元素。比如对于数组[2, 7, 3, 6],我们遍历到3了,我们是不是要判断一下,这个元素和我们是否之前遍历过的元素之和能不能等于我们的target
  • 因为我们不仅要知道这个元素是多少,还要知道这个元素在数组里的下标。那么就很明显了,我们需要用map来存放这种数据结构。
    • 并且我们将元素作为key,下标作为value。那么为什么不将下标作为key,元素作为value呢?那就看我们到底要查找的是什么,首先一点,我们关注该元素是否出现过,所以将要查找的值作为key,这样才能达到我们的要求。map的作用就是在最快的时间内,key是否在这个map中出现过。

综上所述,我们要用map来存放我们遍历过的元素,拿正在遍历的元素与map中的元素比较即可。后面为了简化代码,我们直接拿target - 正在遍历的元素,去看map是否有元素符合

map解题过程

map在本题中最重要的功能就是存放我们遍历过的元素。

对于nums = [2, 7, 3, 6] target:9

当我们遍历到2,我们就想找一下元素7是否被遍历,因为2+7=9.所以我们要到map里面去查询。这就体现出了我们map的功能

所以我们把2放到map中,key = 2, value = 0;并且在map里搜索7,搜不到,继续遍历数组;

当遍历到第二个元素7,查询元素2,因为7+2=9。再去map中查询。发现map里面有!那么就找到了一个符合要求的结果集。

伪代码

unordered_map (int, int) map;
//遍历数组
for (i = 0; i < nums.size; i++)
{s = target - nums[i];iter = map.find(s);if(iter != map.end)	//查找这个元素在map里出现过return (iter->value, i);//如果没有在map中找到符合要求的元素,我们把当前元素存入mapmap.insert(nums[i], i);
}
//遍历之后仍然没找到
return null;

C++代码

class Solution {
public:vector<int> twoSum(vector<int>& nums, int target) {std::unordered_map <int,int> map;for(int i = 0; i < nums.size(); i++) {// 遍历当前元素,并在map中寻找是否有匹配的keyauto iter = map.find(target - nums[i]); if(iter != map.end()) {return {iter->second, i};}// 如果没找到匹配对,就把访问过的元素和下标加入到map中map.insert(pair<int, int>(nums[i], i)); }return {};}
};

454.四数相加II

力扣题目链接

其实总之一句话,就是把四数相加简化成两数相加。

整体思路

  • 为什么用到哈希表。

对于数组A、B、C、D。一个简单的思路,用4个for循环进行遍历,等于0就count++,时间复杂度是O(n^4)。那么我们是不是可以只遍历A、B两个数组,我把这两个数组取出的元素a+b放到一个集合.然后再遍历C、D两个数组,把从其中取出来的元素c+d,那这个去判断存入了a+b元素的集合里有没有我们想要的元素,如果有,就count++.

  • 用什么样的哈希结构解这个题呢?

这道题中,由于有➕操作,所以元素数值可能是很大的,如果用数组下标做映射,大概率不够。所以我们只能考虑set和map。又因为本题中,我们不仅要记录a+b,还要记录a+b等于同样数值的出现次数,因为题目要求我们返回符合要求的元组个数。

综上所述,我们需要用map来解决此题

map解题过程

总结一下思路

我们在A、B数组找到了a+b作为map的key,然后其出现的次数作为value。我们要将C、D中的c+d作为查询,到map中查找符合要求的a+b。

  • 注意:我们拿c+d进行查询的时候,是拿0-(c+d)这个元素有没有出现在map集合中。然后我们把对应的a+b次数都算到count里面

注意事项

为什么遍历A、B和C、D而不是遍历A,然后遍历B、C、D呢?

答:时间复杂度更低

如果对于0-(c+d)的查询,在map中找到了对应的(a+b)。此时我们的count应该加多少呢?

答:记录该a+b对应的value

伪代码

unordered_map(int, int);
for(a:A)
{for(b:B){map[a+b]++;}
}for(c:C)
{for(d:D){target = 0 - (c + d);if (map.find(target != map.end))count += map[target];}
}
return count;

C++代码

class Solution {
public:int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {unordered_map<int, int> umap; //key:a+b的数值,value:a+b数值出现的次数// 遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中for (int a : A) {for (int b : B) {umap[a + b]++;}}int count = 0; // 统计a+b+c+d = 0 出现的次数// 在遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就把map中key对应的value也就是出现次数统计出来。for (int c : C) {for (int d : D) {if (umap.find(0 - (c + d)) != umap.end()) {count += umap[0 - (c + d)];}}}return count;}
};

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

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

相关文章

PagePlug多条件查询方案

正确实现 使用Case When来编写查询条件 SELECT * FROM pc_ticket_tax_cloud WHERE 11 AND (CASE WHEN {{data_table.searchText ! }} THEN xsddm like {{data_table.searchText || ""}}%ELSE 11 END ) AND (CASE WHEN {{doc_code_input.text ! }} THEN doc_code li…

【C语言算法】求逆序对数目(C语言+归并排序)

题目描述 Background Raymond Babbitt drives his brother Charlie mad. Recently Raymond counted 246 toothpicks spilled all over the floor in an instant just by glancing at them. And he can even count Poker cards. Charlie would love to be able to do cool thin…

代码随想录Day31

Day 31 贪心算法 Part01 今日任务 455.分发饼干 摆动序列 最大子序和 代码实现 455.分发饼干 //自己想的&#xff0c;虽然看着不让代码随想录给出的解法简洁&#xff0c;但是理论是一样的public int findContentChildren(int[] g, int[] s) {Arrays.sort(g);Arrays.sort(…

Git浅谈配置文件和免密登录

一、文章内容 简述git三种配置ssh免密登录以及遇见的问题git可忽略文件git remote 相关操作 二、Git三种配置 项目配置文件(局部)&#xff1a;项目路径/.git/config 文件 git config --local user.name name git config --local user.email 123qq.cc全局配置文(所有用户): …

【Web】记录CISCN 2021 总决赛 ezj4va题目复现——AspectJWeaver

目录 前言 原理分析 step 0 step 1 EXP 前文&#xff1a;【Web】浅聊Java反序列化之AspectJWeaver——任意文件写入-CSDN博客 前言 这就是当年传说中的零解题嘛&#x1f62d;&#xff0c;快做&#x1f92e;了 有了之前的经验&#xff0c;思路顺挺快的&#xff0c;中间不…

网络基础(一)初识

1、计算机网络背景 1.1、网络发展 1. 独立模式: 计算机之间相互独立&#xff1b; 2. 网络互联: 多台计算机连接在一起&#xff0c;完成数据共享&#xff1b; 3. 局域网LAN: 计算机数量更多了, 通过交换机和路由器连接在一起; 4. 广域网WAN: 将远隔千里的计算机都连在一起;…

突破编程_C++_STL教程( priority_queue 的基础知识)

1 std::priority_queue 概述 std::priority_queue 是 C 标准库中的一个容器适配器&#xff0c;它提供了一种实现优先队列数据结构的机制。优先队列是一种特殊的队列&#xff0c;其中元素的出队顺序不是基于它们进入队列的顺序&#xff0c;而是基于它们的优先级。优先级最高的元…

【python】python汽车效能数据集—回归建模(源码+数据集)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

yaml 语法和在线解析工具

文章目录 在线解析工具1. 简介2. 语法规则3. 数据类型3.1 数组&#xff1a;3.2对象&#xff1a;3.3 标量3.4 复合结构3.5 锚点3.5.1 单个锚点3.5.6 多个锚点 3.6 引号 参考 在线解析工具 工具1 工具2 1. 简介 Yaml是一种可读性高的数据标记语言&#xff0c;Yaml文件是一种配…

使用VisualStudio集成开发nodejs的addon项目

文章目录 Visual Studio中的nodeJS项目配置Visual Studio中的addon项目配置一般的addon项目手写CPP文件 & VS构建.node文件的本质分析使用VS来创建node文件项目另外一个验证方式Visual Studio中的nodeJS项目配置 在VisualStudio的IDE中,已经可以创建一些基本的nodejs项目…

vscode配置C语言打断点

搞了半天&#xff0c;也不知道为什么&#xff0c;不能打断点&#xff0c;后来就可以了。 1&#xff0c;VSCODE启动要管理员启动。 launch.json文件内容 { "version": "0.2.0", "configurations": [ { "name": "(Windows) Laun…

Python从入门到精通秘籍十五

一、Python之基础地图的使用 当涉及到地图数据和地理信息处理时&#xff0c;Python中最常用的库是Folium&#xff0c;它是一个基于Leaflet.js的Python库&#xff0c;可以轻松创建交互式地图可视化。 首先&#xff0c;你需要安装Folium库。可以通过以下命令使用pip进行安装&am…

45.i++和++i

目录 一.基本概念 二.区别 三.总结 四.视频教程 一.基本概念 i和i两者的作用都是自增加1。单独使用的话&#xff0c;i和i&#xff0c;效果都是一样的&#xff0c;就是ii1。 int main() {int i 0;i; } int main() {int i 0;i; } 最后的结果都是1。 二.区别 如上单独使…

SpringBoot—@ConditionalOnBean与@ConditionalOnClass

一、ConditionalOnBean概念 需求场景 比如下面一种场景&#xff0c;我在实例化People对象的时候&#xff0c;需要注入一个City对象。这个时候问题来了&#xff0c;如果city没有实例化&#xff0c;那么下面就会报空指针或者直接报错。 所以这里需求很简单&#xff0c;就是当前c…

就业班 第二阶段 2401--3.19 day4 主从复制

一、MySQL-Replication&#xff08;主从复制&#xff09; 1.1、MySQL Replication 主从复制&#xff08;也称 AB 复制&#xff09;允许将来自一个MySQL数据库服务器&#xff08;主服务器&#xff09;的数据复制到一个或多个MySQL数据库服务器&#xff08;从服务器&#xff09;…

MySQL面试题--最全面-索引

目录 一、索引 1.MySQL是如何让实现的索引机制&#xff1f; 2.InnoDB索引与MyISAM索引实现的区别是什么&#xff1f; 3.一个表中如果没有创建索引&#xff0c;那么还会创建B树吗&#xff1f; 4.说一下B树索引实现原理&#xff08;数据结构&#xff09; 5.聚簇索引与非聚簇…

Handler的post与sendMessage的区别和应用场景

Handler的post与sendMessage的区别和应用场景 区别在于post实现起来比较简单。而sendMessage()则需要自己重写handleMessage&#xff08;&#xff09;方法。 两者在本质上都没有什么区别。post方法适合单一的场景&#xff0c;实现起来比较方便。sendMessage()适合需要作条件判…

弱电工程包括哪些工程?

​一、弱电工程的分部有哪些? 分为基础、主体、装饰工程、强电、弱电、消防、暖通、给排水工程&#xff0c;桩基、筏板、模板、钢筋、混凝土、砌体、粉刷、地坪等 二、弱电工程系统包括哪些? 弱电系统包括&#xff1a;闭路电视监控系统、防盗报警系统、门禁系统、电子巡更…

[小程序开发] 分包加载

一、介绍 分包加载是一种小程序的优化技术&#xff0c;将小程序不同功能的代码&#xff0c;分别打包成不同的子包&#xff0c;在构建时打包成不同的分包&#xff0c;用户在使用时按需进行加载&#xff0c;在构建小程序分包项目时&#xff0c;构建会输出一个或多个分包&#xff…

突破编程_C++_C++11新特性(type_traits的复合类型特性以及关系类型特性)

1 type_traits 复合类型特性 1.1 std::is_function std::is_function 是一个模板类&#xff0c;用于检查一个类型是否为函数类型。 定义&#xff1a; template< class T > struct is_function;当 T 为函数类型则为 true&#xff0c;否则为 false。 样例&#xff1…