242.有效的字母异位词
题目链接:https://leetcode.cn/problems/valid-anagram/description/
思路:首先要明确字母异位词的定义,即两字符串中的每个字符出现的次数相同。考虑到字符会重复出现,这时需要用到哈希法,该题的字符较少,可以用数组这一数据结构。数组大小为26,对应a-z这26个连续的字母。在遍历字符串s的时候,只需要将 s[i] - ‘a’ 所在的元素做+1 操作即可,并不需要记住字符a的ASCII,只要求出一个相对数值存放在数组中。
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; //record数组中的所有元素都为0,说明两字符串是字母异位词
}
};
349. 两个数组的交集
题目链接:https://leetcode.cn/problems/intersection-of-two-arrays/description/
思路:该题用到了一个哈希法新的数据结构,即set(集合),unordered_set。std::unordered_set的底层实现是哈希表, 使用unordered_set 读写效率是最高的,并不需要对数据进行排序,而且还不要让数据重复,所以选择unordered_set。该题出现了迭代器的概念,由于没有接触过,所以这到题感觉很难。
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) { //使用set结构体作哈希表来处理没有限制数值的问题
unordered_set<int> result_set; //存放结果,set能给结果去重
unordered_set<int> nums_set(nums1.begin(), nums1.end()); //创建nums_set 将nums1数组中的元素添加到其中,nums1.begin()和nums1.end()分别表示nums1数组的起始和结束迭代器。
for (int num : nums2) { //范围基于循环 遍历nums2数组中的每个元素,将每个元素赋值给变量num。
// 发现nums2的元素 是否在nums_set里出现过 ==end了就说明set里面没有这个元素。
if (nums_set.find(num) != nums_set.end()) {
result_set.insert(num);
}
}
return vector<int>(result_set.begin(), result_set.end()); //unordered_set<int>是一个无序集合,不保持元素的插入顺序。vector<int>是一个有序的动态数组,保持元素的插入顺序。 unordered_set 来存储交集结果,以便去重。函数的返回类型要求是 vector<int>,因此我们需要将 result_set 转换为这种类型。
}
};
202. 快乐数
题目链接:https://leetcode.cn/problems/happy-number/
思路:先要写一个求取数值各个位上的单数之和的函数。然后要判断sum是否会重复出现集合里,重复了就是return false,没重复直接找到sum等于1为止。所以需要考虑哈希法。哈希法的数据结构采用unordered_set。注意无限循环的条件while(1)及跳出循环的条件。
class Solution {
public:
int getSum(int n){
int sum = 0;
while(n>0){ //取数值各个位上的单数之和(正整数)
sum += (n%10)*(n%10);
n = n/10;
}
return sum;
}
bool isHappy(int n) {
unordered_set<int> set;
while(1){ //无限循环,当条件为真,一直执行循环体中的语句 直到程序被强制停止或满足特定条件才退出循环。
int sum = getSum(n);
if(sum == 1){
return true;
}
//如果这个sum出现过,说明已经进入无限循环,立刻false; set.end()指向null;
if(set.find(sum) != set.end()){//sum在set中都没有出现过
return false;
}else {
set.insert(sum); //将sum插入set容器中
}
n = sum; //保证循环的执行
}
}
};
1. 两数之和
题目链接:https://leetcode.cn/problems/two-sum/
思路:该题较难,用到了哈希法里的map数据结构,map中的数据是以<key,value>形式储存的,key来存元素,value来存下标,同时也用到了迭代器的概念。std::unordered_map 底层实现为哈希表。map目的用来存放我们访问过的元素,因为遍历数组的时候,需要记录我们之前遍历过哪些元素和对应的下标,这样才能找到与当前元素相匹配的(相加等于target)。
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]); //iter作为一个迭代器,其指向哈希表中的某个元素,
if(iter != map.end()){ //如果 iter 不等于哈希表的 end(),说明找到了对应的差值,可以继续处理。
return {iter->second, i}; //数组中的值以<key,value>保存到map中去,iter->second 表示该元素的第二个值,也就是哈希表中存储的索引。返回一个包含两个整数的数组,第一个整数是哈希表中存储的索引,第二个整数是当前遍历的数组索引。
}//如果没找到匹配对,就把访问过的元素和下标加入到map中
map.insert(pair<int,int>(nums[i],i)); //pair用于存储两个不同类型的值。
}
return {};
}
};
总结:什么时候使用哈希法,当我们需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,就要第一时间想到哈希法。