242.有效的字母异位词
思路
这个题目其实很简单,用普通的哈希表就可以解决,把连续字符的出现放在连续的数组里,用下标分别表示不同的字符,重点是理解这种方法,过程我就不赘述啦。
代码实现
class Solution {
public:
bool isAnagram(string s, string t) {
int hash[26]={0};
for(int i=0;i<s.size();i++){
hash[s[i]-'a']++;
}
for(int i=0;i<t.size();i++){
hash[t[i]-'a']--;
}
for(int i=0;i<26;i++){
if(hash[i]!=0)return false;
}
return true;
}
};
总结
想一般哈希表都是用来快速判断一个元素是否出现集合里,就用哈希表。暴力法可以解决但是时间复杂度一般是成倍数增长。
349. 两个数组的交集
思路
我的第一反应还是使用数组,但是这样会有一个问题,就是无法确定数组的空间到底需要多少,看了卡哥的讲解我才知道原来神奇的STL里还有unordered_set这样的好东西。
它的底层逻辑还是一个哈希表,只不过是一个无序哈希表。使用unordered_set 读写效率是最高的,并不需要对数据进行排序,而且还不要让数据重复,用find( )、insert( )、end( ),操作快捷又避免元素重复。
代码实现
1.unordered_set实现
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());
}
};
- unordered_map实现
class Solution {
public:
vector<int> intersection(vector<int>& s, vector<int>& t) {
unordered_map<int,int> hash;
vector<int> result;
for(int i=0;i<s.size();i++){
hash[s[i]]++;
}
for(int i=0;i<t.size();i++){
if(hash.find(t[i])!=hash.end()&&hash[t[i]]!=0){
result.push_back(t[i]);
hash[t[i]]=0;
}
}
return result;
}
};
总结
用unordered_set输出结果中的每个元素一定是唯一的,也就是说输出的结果的去重的, 数据大小不确定的,同时可以不考虑输出结果的顺序时可以用unordered_set。set初始化的方法也要记得。
注:return的数据是vector的,要经过一个转化过程:
vector(result_set.begin(), result_set.end())
用unordered_map也挺方便的,num1里面的元素记录hash表内,如果表内存在num2内的元素放入result结果集就好了。
202. 快乐数
思路
看见这个题目我其实是没什么思路的(脑袋比较不灵活😢)。然后学习到了一个新的方法,就是发现得到的sum值重复时就证明进入了循环(妙啊!)。所以这道题的思路就是把把sum存起来,然后发现新得到的sum和set里面的某个数据一样就可以return false啦。
代码实现
class Solution {
public:
bool isHappy(int n) {
unordered_set<int> hash;
while(n){
if(n==1)return true;
int tmp=n;
int sum=0;
while(tmp){
sum+=(tmp%10)*(tmp%10);
tmp/=10;
n=sum;
}
if(hash.find(n)!=hash.end())return false;
else hash.insert(n);
}
return 0;
}
};
总结
确实挺不错的哈哈哈。不多说,和上一道题差不多。
1. 两数之和
思路
再强调一下 什么时候使用哈希法:当我们需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,就要第一时间想到哈希法。
这道题就是判断两元素什么时候之和会满足条件,显而易见又是哈希。我们不仅要知道元素有没有遍历过,还要知道这个元素对应的下标,需要使用 key value结构来存放,key来存元素,value来存下标,那么使用map正合适。
为什么不用数组或set呢?
- 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
- set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,不仅要判断y是否存在而且还要记录y的下标位置,因为要返回x 和 y的下标。所以set也不能用。
代码实现
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中寻找是否有匹配的key
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 {};
}
};
时间复杂度: O(n)
空间复杂度: O(n)
总结
一刷:学到了些新的东西:
- unordered_map并不需要key有序,选择unordered_map 效率更高
- 当需要查找且返回一些数据时用map
- map.insert(pair<int,int>(key,value)),insert的元素不要弄错了哦
- return空vector时需要用{ }
二刷:第一反应是采用排序后双指针的方法了,但是忽略了相同元素的情况,所以还是一刷学的方法更好,还是需要重复记忆啊哈哈哈。
小记
一刷:今天有点忙,但是明天只会更忙,但更忙也要坚持,加油加油加油!😆😆😆
二刷:最近有点懈怠了,没跟上大部队,加油补上。