代码随想录算法训练营第七天|454.四数相加II、383. 赎金信、15. 三数之和、18. 四数之和
今日学习的文章和视频链接
454文章链接: link
454视频讲解链接: link
383文章链接: link
383视频暂无讲解
15文章链接: link
15视频讲解链接: link
18文章链接: link
18视频讲解链接: link
第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
解题思路:四数相加不用考虑去重,所以想到使用哈希表来处理本题。
我们不仅要记录a + b在集合里出现,还要统计a + b出现过多少次,之后在可以和c + d做一个映射。所以我们不仅要统计是否出现过,还要统计出现过的次数。所以我们选择使用map,用key存是否出现过,value存出现过的次数。
看完代码随想录后的想法
解题步骤:
- 首先定义 一个unordered_map,key放a和b两数之和,value 放a和b两数之和出现的次数。
- 遍历nums1和nums2数组,统计两个数组元素之和,和出现的次数,放到map中。
- 定义int变量count,用来统计 a+b+c+d = 0 出现的次数。
- 再遍历nums3和nums4数组,找到如果 0-(c+d) 在map中出现过的话,就用count把map中key对应的value也就是出现次数统计出来。
- 最后返回统计值 count 。
实现过程中遇到的困难
最开始的时候想到了先遍历一个数组,然后再遍历另外三个数组是否在对应集合中出现过。这样再遍历后面三个数组时,时间复杂度为O( n 3 n^3 n3),而先遍历前两个数组,再遍历后两个数组的时间复杂度为 O ( n 2 ) O(n^2) O(n2)。
代码
class Solution {public:int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {unordered_map<int, int> umap; //key:a+b的数值,value:a+b数值出现的次数// 遍历nums1和nums2数组,统计两个数组元素之和,和出现的次数,放到map中for (int a : nums1) {for (int b : nums2) {umap[a + b]++;}}int count = 0; // 统计a+b+c+d = 0 出现的次数// 在遍历nums3和nums4数组,找到如果 0-(c+d) 在map中出现过的话,就把map中key对应的value也就是出现次数统计出来。for (int c : nums3) {for (int d : nums4) {if (umap.find(0 - (c + d)) != umap.end()) {count += umap[0 - (c + d)];}}}return count;}
};
383. 赎金信
看到题目第一想法
题目描述:给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。
如果可以,返回 true ;否则返回 false 。
magazine 中的每个字符只能在 ransomNote 中使用一次。
解题思路:发现本题与之前的242.有效的字母异位词相似,只是本题是求 字符串a能否组成字符串b,而不用管字符串b 能不能组成字符串a。
看完代码随想录后的想法
判断第一个字符串ransom能不能由第二个字符串magazines里面的字符构成时需注意两点:
- 第一点“magazine 中的每个字符只能在 ransomNote 中使用一次”
- 第二点ransomNote 和 magazine 由小写英文字母组成
因为本题目只有小写字母,所以采用一个长度为26的数组来记录magazine里字母出现的次数。
再用ransomNote去验证这个数组是否包含ransomNote所需的所有字母。
使用哈希法来解决本题。
实现过程中遇到的困难
本想着使用map,但是感觉有点大材小用,看了代码随想录了解到在本题的情况下,使用map的空间消耗要比数组大一些的,因为map要维护红黑树或者哈希表,而且还要做哈希函数,是费时的!数据量大的话就能体现出来差别了。 所以数组更加简单直接有效!
代码
class Solution {public:bool isAnagram(string s, string t) {int record[26]={0};for(int i = 0;i < s.size();i++){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){return false;}}return true;}
};
第15题. 三数之和
看到题目第一想法
题目描述:
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意: 答案中不可以包含重复的三元组。
解题思路:依然想着使用哈希法去解决本问题,但题目中要求我们去重,但是对去重的部分思路不是很清晰。
看完代码随想录后的想法
随想录中给了哈希法和双指针法两种解法。
哈希法
先使用两层for循环确定a + b,然后使用哈希法来确定 0-(a+b) 是否在 数组里出现过。
但要把符合条件的三元组放进vector中,然后再去重,这样是非常费时的,很容易超时。
时间复杂度可以做到O(n^2),但还是比较费时的,因为不好做剪枝操作。
双指针法
双指针法要比哈希法高效,我们看如下动画:
首先将数组排序,然后有一层for循环,i从下标0的地方开始,同时将一个下标left 定义在i+1的位置上,定义下标right 在数组结尾的位置上。
依然还是在数组中找到 abc 使得a + b +c =0,我们这里相当于 a = nums[i],b = nums[left],c = nums[right]。
移动left 和right:
- 如果nums[i] + nums[left] + nums[right] > 0 就说明 此时三数之和大了,因为数组是排序后了,所以right下标就应该向左移动,这样才能让三数之和小一些。
- 如果 nums[i] + nums[left] + nums[right] < 0 说明 此时 三数之和小了,left 就向右移动,才能让三数之和大一些。
直到left与right相遇为止。
实现过程中遇到的困难
对去重的操作还不是很熟悉
去重逻辑思考
其实主要考虑三个数的去重。 a, b ,c, 对应的就是 nums[i],nums[left],nums[right]
a的去重
a 如果重复了怎么办,a是nums里遍历的元素,那么应该直接跳过去。
但是是判断 nums[i] 与 nums[i + 1]是否相同,还是判断 nums[i] 与 nums[i-1] 是否相同?都是和 nums[i]进行比较,是比较它的前一个,还是比较他的后一个?
如果我们比较它的后一个:
if (nums[i] == nums[i + 1]) { // 去重操作continue;
}
那就我们就把 三元组中出现重复元素的情况直接pass掉了。 例如{-1, -1 ,2} 这组数据,当遍历到第一个-1 的时候,判断 下一个也是-1,那这组数据就pass了。
但要记住我们是不能有重复的三元组,但三元组内的元素是可以重复的!
此时这里是有两个重复的维度。
所以应该比较它的前一个:
if (i > 0 && nums[i] == nums[i - 1]) {continue;
}
这么写就是当前使用 nums[i],我们判断前一位是不是一样的元素,在看 {-1, -1 ,2} 这组数据,当遍历到 第一个 -1 的时候,只要前一位没有-1,那么 {-1, -1 ,2} 这组数据一样可以收录到 结果集里。
b与c的去重
当去重的逻辑中加入
代码
class Solution {public:vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {unordered_set<int> result_set;unordered_set<int> nums_set(nums1.begin(),nums1.end());for(int num : nums2){if(nums_set.find(num) != nums_set.end()){result_set.insert(num);}}return vector<int>(result_set.begin(),result_set.end());}
};
第202题. 快乐数
看到题目第一想法
题目描述:
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
如果 n 是快乐数就返回 True ;不是,则返回 False 。
有如下想法:
关键:** 若无限循环,那么求和的过程中,sum会重复出现**
所以采用哈希法来判断这个sum是否重复出现,如果重复了就是return false, 否则一直找到sum为1为止。
判断sum是否重复出现就可以使用unordered_set。
看完代码随想录后的想法
思路相同
实现过程中遇到的困难
对取数值各个位上的单数操作不是很熟悉
代码
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. 两数之和
看到题目第一想法
题目描述:
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
本题解决有困难,对map不是很了解。
看完代码随想录后的想法
本题需要一个集合来存放我们遍历过的元素,然后在遍历数组的时候去询问这个集合,某元素是否遍历过,也就是 是否出现在这个集合。
本题我们不仅要知道元素有没有遍历过,还要知道这个元素对应的下标,需要使用 key value结构来存放,key来存元素,value来存下标,那么使用map正合适。
为何使用之前用过的set呢?
- 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
- set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,不仅要判断y是否存在而且还要记录y的下标位置,因为要返回x 和 y的下标。所以set 也不能用。
而map是一种key value的存储结构,可以用key保存数值,用value在保存数值所在的下标。
在map在C++的3种类型中,选择std::unordered_map,因为这道题目中并不需要key有序,选择std::unordered_map 效率更高。
使用map需注意如下两点:
- map用来做什么
- map中key和value分别表示什么
关于第一点,map目的用来存放我们访问过的元素,因为遍历数组的时候,需要记录我们之前遍历过哪些元素和对应的下标,这样才能找到与当前元素相匹配的(也就是相加等于target)
关于第二点,这道题我们需要给出一个元素,判断这个元素是否出现过,如果出现过,返回这个元素的下标。
判断元素是否出现,这个元素就要作为key,所以数组中的元素作为key,有key对应的就是value,value用来存下标。
所以 map中的存储结构为 {key:数据元素,value:数组元素对应的下标}。
在遍历数组的时候,只需要向map去查询是否有和目前遍历元素比配的数值,如果有,就是找到的匹配对,如果没有,就把目前遍历的元素放进map中,因为map存放的就是我们访问过的元素。
实现过程如下图:
实现过程中遇到的困难
对取数值各个位上的单数操作不是很熟悉
代码
今日收获
1.对哈希表的基础理论有所了解
2.知道了set和map的应用场景
3.使用模板库还是不太熟练,后续需要加强
今日学习时长3h
该文章图片均来自Carl哥的代码随想录,在此特别感谢
代码随想录算法训练营第七天|454.四数相加II、383. 赎金信、15. 三数之和、18. 四数之和相关推荐
- 代码随想录算法训练营day6| 454.四数相加II 383.赎金信 15.三数之和 18.四数之和
代码随想录算法训练营day6| 454.四数相加II 383.赎金信 15.三数之和 18.四数之和 LeetCode 454 四数相加II 题目链接: 454.四数相加II class Soluti ...
- 代码随想录算法训练营第七天|454.四数相加II ● 383. 赎金信 ● 15. 三数之和 ● 18. 四数之和
一.454.四数相加II 力扣 思路:第一眼还没反应过来,真是缺练.在四个数组中分别寻找,可以先把前两个数组的和先存入map中,再计算后两个数组元素的和,看一下相反数在map中出现没有,出现过就res ...
- 代码随想录算法训练营第6天 | 454. 四数相加 II 383. 赎金信 15. 三数之和 18. 四数之和
一.Leetcode 454. 四数相加 II 相当于两数相加.但是呢很巧妙的是,卡哥在遍历CD数组时把查哈希表的方法融入了进去.学习一下. 二.Leetcode 383. 赎金信 更简单了,主要是审 ...
- 代码随想录算法训练营第七天 | 454. 四数相加 II、383. 赎金信、15. 三数之和、18. 四数之和
454. 四数相加 II 题解及想法 通过两个for循环先遍历a和b,key放a和b两数之和,value 放a和b两数之和出现的次数,再通过两个for循环遍历c和d,如果0-(c+d) 在map中出现 ...
- 代码随想录算法训练营第七天| 454.四数相加II,383. 赎金信,15. 三数之和,18. 四数之和
Leetcode 454.四数相加II 思路分析: 本题直观的想法是采取暴力法,四数相加就用四层for循环.虽然能得到结果,但时间复杂度为o(n4),当数组长度较大时,Leetcode便提示超时.该方 ...
- 代码随想录算法训练营第七天|454、四数相加Ⅱ 383、赎金信15、三数之和18、四数之和
454.四数相加Ⅱ.383.赎金信.15.三数之和四数之和 四数相加 对于四数相加,我们可以定义一个map用来记录nums1与nums2的和对应次数,再遍历nums3与nums4,如果存在c与d使得a ...
- 代码随想录算法训练营第七天| 454.四数相加II 、383. 赎金信 、15. 三数之和 、18. 四数之和 。
454.四数相加II 题目链接 给你四个整数数组 nums1.nums2.nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足: 0 <= i ...
- 代码随想录算法训练营第七天| 454.四数相加II 、383. 赎金信、15. 三数之和、18. 四数之和
454. 四数相加 II 题目: 给你四个整数数组 nums1.nums2.nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足: 0 <= ...
- 代码随想录算法训练营第七天 | 454.四数相加II ,383. 赎金信 ,15. 三数之和,18. 四数之和
一.参考资料 四数相加II 题目链接/文章讲解/视频讲解:https://programmercarl.com/0454.%E5%9B%9B%E6%95%B0%E7%9B%B8%E5%8A%A0II. ...
最新文章
- kepserver 三菱fx_#电工培训# #plc培训# PLC培训 学在智通 赢在职场【三菱plc吧】
- stm32f4 RAM中运行程序 读保护设置
- gitlab 开源项目 星_49必须了解的机器学习开源项目,Github上平均3600星
- nginx之rtmp模块引用计数设计
- fasttext的基本使用 java 、python为例子
- 7-37 模拟EXCEL排序 (25 分)(思路+详解+超时解决 兄弟们冲呀呀呀呀呀呀)
- 简要描述内部连接和外部连接之间的区别_sqlserver的几种常见连接方法
- emlog简洁大气白色风格资源站模板源码
- python把csv做成柱状图_用Python的Matplotlib模块实现CSV数据格式的可视化
- 20200721每日一句
- 2021-08-31Flink 中的核心概念和基础考察
- Eprime与EEG的接口
- ssci源刊里有开源期刊吗_SSCI和SCI期刊投稿指南-以经济学和管理学为例
- win10开机就卡死在桌面上怎么解决
- sublime text 提示error while loading pyvb binvry:exit code3 try tomanually install pyvb的处理方法
- CSS基础 | (1) CSS是什么
- Composer修改镜像源
- Android学习记录
- android 装饰着模式,Android与设计模式——装饰者(Decorator)模式
- 上海市计算机学会-买二送一
热门文章
- 关于计算机的英语手抄报简单,简单漂亮的英语手抄报图片大全
- jQuery常用方法汇总
- win10 64位安装绿色版mysql-5.7.16-winx64
- 如何测试服务器及端口是否畅通
- SEEDLAB2.0-Spectre Attack Lab
- npm install安装报错 gyp info it worked if it ends with ok
- 专家称我国带薪休假制度偏重单位利益-长假-黄金周-带薪休假
- HTML中的position属性
- event对象的一些方法(取消冒泡,阻止默认行为)
- Ubuntu下Pycharm切换中文输入法无法输入中文解决方法