【leetcode_C++_哈希表_day5】242. 有效的字母异位词&&349. 两个数组的交集&&202.快乐数&&1. 两数之和
C++知识补充:(不完全,仅针对本题用的知识点)
1.C++类 & 对象

关键字 public 确定了类成员的访问属性。在类对象作用域内,公共成员在类的外部是可访问的。您也可以指定类的成员为 private 或 protected,这个我们稍后会进行讲解。
2.C++ STL
C++ STL(标准模板库)是一套功能强大的 C++ 模板类,提供了通用的模板类和函数,这些模板类和函数可以实现多种流行和常用的算法和数据结构,如向量、链表、队列、栈。
C++ 标准模板库的核心包括以下三个组件:
| 组件 | 描述 |
|---|---|
| 容器(Containers) | 容器是用来管理某一类对象的集合。C++ 提供了各种不同类型的容器,比如 deque、list、vector、map 等。 |
| 算法(Algorithms) | 算法作用于容器。它们提供了执行各种操作的方式,包括对容器内容执行初始化、排序、搜索和转换等操作。 |
| 迭代器(iterators) | 迭代器用于遍历对象集合的元素。这些集合可能是容器,也可能是容器的子集。 |
#include <iostream>
#include <vector>//首先要添加头文件
using namespace std;
int main()
{
// 创建一个向量存储 int
vector<int> vec;
int i;
// 显示 vec 的原始大小:vec.size()
cout << "vector size = " << vec.size() << endl;
// 推入 5 个值到向量中:vec.push_back(i);
for(i = 0; i < 5; i++){
vec.push_back(i);
}
// 显示 vec 扩展后的大小
cout << "extended vector size = " << vec.size() << endl;
// 访问向量中的 5 个值
for(i = 0; i < 5; i++){
cout << "value of vec [" << i << "] = " << vec[i] << endl;
}
// 使用迭代器 iterator 访问值
vector<int>::iterator v = vec.begin();
while( v != vec.end()) {
cout << "value of v = " << *v << endl;
v++;
}
return 0;
}
3.哈希表
给一个元素判断在这个集合中是否出现过,这种场景要想到哈希表。
哈希法是牺牲了空间换取了时间。
根据具体问题分析用:
🔸数组:数据量小且集中
通过leetcode242. 有效的字母异位词体验哈希表的数组应用。
🔸set(集合):数据量大且分散
std::set
std::multiset
std::unordered_set
再来看一下使用数组和set来做哈希法的局限。
- 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
- set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,不仅要判断y是否存在而且还要记录y的下标位置,因为要返回x 和 y的下标。所以set 也不能用。
set是一个集合,会自动给元素排序,从小到大
头文件
#include <set>

🔸map(映射):map是一种key value的存储结构,可以用key保存数值,用value在保存数值所在的下标。
通过leetcode1. 两数之和来体验map的使用吧!
std::map
std::multimap
std::unordered_map
头文件
会自动给元素排序,从小到大,如果是字符串就按照ASCLL码排序
#include <map>

//unordered_map和unordered_set 就是不会排序的map和set。节省运行时间的时候可以用.效率更高。
//不会排序不代表会按照原来的顺序输出。会以一种随机的顺序输出。
#include <unordered_map>
#include <unordered_set>
242. 有效的字母异位词
1.题目
给定两个字符串 *s* 和 *t* ,编写一个函数来判断 *t* 是否是 *s* 的字母异位词。
注意:若 *s* 和 *t* 中每个字符出现的次数都相同,则称 *s* 和 *t* 互为字母异位词。
示例 1:
输入: s = "anagram", t = "nagaram"
输出: true
示例 2:
输入: s = "rat", t = "car"
输出: false
2.分析
C语言版本:注意:字符的长度判断函数:strlen
bool isAnagram(char * s, char * t){
int record[26]={0};
for(int i=0;i<strlen(s);i++)
record[s[i]-'a']++;
for(int i=0;i<strlen(t);i++)
record[t[i]-'a']--;
for(int i=0;i<26;i++)
{
if(record[i]!=0)
{
return false;
}
}
return true;
}
C++版本:
class Solution {
public:
bool isAnagram(string s, string t) {
int i;
int record[26]={0};//数组初始化
for(i=0;i<s.size();i++)
{
record[s[i]-'a']++;
}
for(i=0;i<t.size();i++)
{
record[t[i]-'a']--;
}
for(i=0;i<26;i++)
{
if(record[i]!=0)
return false;
}
return true;
}
};
349. 两个数组的交集
给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
示例 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] 也是可通过的
思路:
- 将nums1去重
- 用nums2的元素和nums1的去重结果进行比较,并返回和num1的元素相同的nums2元素
- 对找到的nums2元素再一次去重,并且返回作为结果
心得:
用哈希表解决是很简单的题目,但是前提是掌握哈希表。
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());//保存nums1的去重结果
for(int num:nums2)//遍历nums2
{
if(nums_set.find(num)!=nums_set.end())//在nums1的去重结果中找到nums2的元素
result_set.insert(num);//把该元素存入result_set
}
return vector<int>(result_set.begin(),result_set.end());//返回result_set的去重结果
}
};
202.快乐数
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」 定义为:
- 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
- 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
- 如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n 是 快乐数 就返回 true ;不是,则返回 false 。
示例 1:
输入:n = 19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1
示例 2:
输入:n = 2
输出:false
思路:
这是一个寻找1的过程。还记得哈希表的应用场景吗?给一个元素判断在这个集合中是否出现过,这种场景要想到哈希表。
我们需要把每一次的平方和结果做成一个集合set,然后判断两个点:1是否在这个集合中出现过-->return true;重复的元素是否在这个集合中出现过(出现了则说明进入了死循环)-->return false
判断sum是否重复出现就可以使用unordered_set。
另外一个难点就是先定义一个每个位置上的数字的平方和的函数getsum。(也不是很难啦)
心得:
要透过现象看本质。
这道题目看上去貌似一道数学问题,但是其实是在集合中找元素。
class Solution {
public:
int getsum(int n)//先定义一个每个位置上的数字的平方和的函数getsum
{
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(set.find(1)!=set.end()) {//找到了1即返回true
return true;
}
if(set.find(sum)!=set.end()){//如果这个sum曾经出现过,说明已经陷入了无限循环了,这种情况时钟变不到1,立刻return false
return false;
}
else{
set.insert(sum);//收集这个sum结果
}
n=sum;
}
}
};
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]
思路:
本题四个重点:
-
为什么会想到用哈希表
以case1为例:访问2的时候就想看看集合里有没有7,访问7的时候就想找找集合里有没有2,如果找到了就可以返回了。注意本题要求返回的是下标。
本题需要一个集合来存放我们遍历过的元素,然后在遍历数组的时候去询问这个集合,某元素是否遍历过,也就是 是否出现在这个集合。
-
哈希表为什么用map
因为map是key value结构,可以用来存元素和其对应的下标。
本题不涉及到排序,所以出于对效率的考虑,使用unordered_map.
心得:
还是要读题,领悟。
要能悟出题目是在找。给一个元素,判断在这个集合中是否出现过,这种场景要想到哈希表。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> map;//注意map的使用
for(int i=0;i<nums.size();i++)
{
auto iter=map.find(target-nums[i]);//**补充:auto**,因为map是结构变量,为了方便就写auto
if(iter!=map.end())//在map中找到了元素
{
return {iter->second,i};//返回两个下标
}
//如果没有找到匹配对,就把访问过的元素和下标加入到map中
map.insert(pair<int,int>(nums[i],i));
}
return {};//遍历完了还没找到,就返回空
}
};
补充:auto
auto的原理就是根据后面的值,来自己推测前面的类型是什么。
auto的作用就是为了简化变量初始化,如果这个变量有一个很长很长的初始化类型,就可以用auto代替。
本文来自博客园,作者:只想毕业的菜狗,转载请注明原文链接:https://www.cnblogs.com/MLcaigou/p/16817553.html
浙公网安备 33010602011771号