代码随想录算法训练营第6天| 242. 有效的字母异位词、349. 两个数组的交集、第202题. 快乐数、1. 两数之和。
学习文档链接: 代码随想录
一、242. 有效的字母异位词
链接: 有效的字母异位词
该题思路:
(1)使用数组:新建一个有26个字符的数组,通过遍历s增加对应的数组值,遍历t减小对应的数组值,最后遍历整个数组,如果数组值均为0,返回true,否则返回false。数组缺点:如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费!
(2)使用unordered_map(char,int),原理与上面一致,不过复杂度相对数组较高。
(1)使用数组,详细代码如下:
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;
}
};
(2)使用unordered_map(char,int),详细代码如下:
/**
*2024-5-13
* 使用unordered_map的key存储元素,value统计次数。此方法复杂度比使用数组高。
**/
class Solution {
public:
bool isAnagram(string s, string t) {
unordered_map<char ,int> myMap;
for(const char &c: s){ //加&表示可以修改c,加const是因为不需要修改。与for(char c: s)相同。因此使用了引用以避免对字符串字符进行复制,这有助于提高效率。
myMap[c] +=1;
}
for(const char &d: t){
myMap[d] -=1;
}
for(const auto &pair:myMap){
if(pair.second!=0){
return false;
}
}
// for(auto it = myMap.begin();it!=myMap.end();it++){
// if(it->second!=0){
// return false;
// }
// }
return true;
}
};
二、349. 两个数组的交集
链接: 两个数组的交集
初始想法:
想到使用set容器了,但是没想到使用find()函数,只想到数值比较,导致在找到值的时候,考虑插入值到result时,不知道如何下手。所以就使用了暴力双重循环,下面将两种思路均写出来,详细代码如下:
(1)暴力遍历法
时间复杂度为o(n^2),详细代码如下:
/**
* 2024-05-13
* 暴力双层循环,时间复杂度o(n^2),想到使用set容器了,但是没想到使用find()函数,只想到数值比较,导致在找到值的时候,考虑插入值到result时,不知道如何下手。
**/
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> mySet;
vector<int> v;
for(const int &a:nums1){
for(const int &b: nums2){
if(a == b){
mySet.insert(b);
}
}
}
for(auto it = mySet.begin();it!=mySet.end();it++){
v.push_back(*it);
}
return v;
}
};
(2)使用set容器
使用unordered_set,同时用find()函数。需要注意的是使用数组初始化set容器时,可用 unordered_set mySet(nums1.begin(),nums1.end());不需要遍历赋值。
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> result;
unordered_set<int> mySet(nums1.begin(),nums1.end());
for(const int &b : nums2){
if(mySet.find(b)!=mySet.end()){
result.insert(b);
}
}
vector<int> res(result.begin(),result.end());
return res;
}
};
三、第202题. 快乐数
链接: 快乐数
初始想法:没有读懂题目的内容,不清楚如何返回false的情况,没有捕捉到无限循环这个信息。
思路:一定要看清楚题目的关键点,就是如果不是快乐数,那么一定会无限循环,那么就可以通过判断该数有没有出现过从而判断是否是快乐数。所以使用哈希set来快速查询该数的情况,使用find()函数来查询是否出现过。
/**
*2024-05-14
* 得到一个数的个、十、百、千等时,就用x%10取余,然后再用x/10取商迭代x,依次就能得到个、十、百、千等。
*/
class Solution {
public:
int getSum(int x){
int sum = 0;
while(x){//x>0时执行
sum += (x%10)*(x%10);
x = x/10;
}
return sum;
}
bool isHappy(int n){
unordered_set<int> mySet;
while(n>=1){
if(n == 1)
return true;
else if(mySet.find(n)!=mySet.end())
return false;
else{
mySet.insert(n);
n = getSum(n);
}
}
return true;
}
};
四、1. 两数之和
链接: 两数之和
思路:
(1)暴力循环
(2)哈希法:查询元素这种情况使用哈希法,从数组、unordered_set、unordered_map这三种中选择,由于n最大为10^4,所以不适合使用数组,数组太过浪费空间,由于题目中不仅需要元素的值,还需要元素的下标,所以不能使用unordered_set,只能使用unordered_map,key存元素值,value存元素下标。
/**
*2024-05-14
*
**/
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> myMap;
vector<int> v;
for(int i =0;i<nums.size();i++){
if(myMap.find(target-nums[i])!=myMap.end()){
auto it = myMap.find(target-nums[i]);
v.push_back(i);
v.push_back(it->second);
}
else
myMap[nums[i]] = i;
}
return v;
}
};
总结
在使用哈希法做题目时,一定要弄清楚映射关系,不然很难做正确。