1.哈希表理论基础
2.有效的字母异位词
代码:
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 j = 0; j < t.size(); j++){
record[t[j] - 'a']--;
}
for(int i = 0; i < 26; i++){
if(record[i] != 0){
return false;
}
}
return true;
}
};
note:用数组来实现这种有限且集中的映射关系,因为只有26个英文字母,因此用数组来做哈希表十分快速便捷。
先用record来统计s字符串里字母的出现次数,再用统计好的record去减去t字符串里的字母的出现次数,如果最后record数组里每个元素都为0,则说明两个字符串确实是有效的字母异位词。
相关题目练习:
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int record[26] = {0};
for(int i = 0 ; i < magazine.size(); i++){
record[magazine[i] - 'a']++;
}
for(int i = 0; i < ransomNote.size(); i++){
record[ransomNote[i] - 'a']--;
}
for(int i = 0; i < 26; i++){
if(record[i] < 0){
return false;
}
}
return true;
}
};
note:magazine字符串里的字母出现次数应该每一个都大于等于ransomNote字符串里的字母出现次数。
这次犯了很多错,比如for循环里的哈希映射关系写错了,而且忘记去减'a'了。。。还是不懂吧。
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
unordered_map<string,vector<string>> mp;
// 把排序后的字符串作为key,value则是原始字符串
for(string& str:strs){
string key = str;
sort(key.begin(),key.end());
mp[key].emplace_back(str);
}
vector<vector<string>> ans;
// 一次添加一个数组
for(auto it = mp.begin(); it != mp.end(); it++){
ans.emplace(it->second);
}
return ans;
}
};
note:主要难以理解的是代码,数据结构嵌合的有点子复杂。
创建一个unordered_map,key是排序后的字符串,vaule是那些排序后的字符串和key一样的字符串数组。我们先把它们分好组后再把这些字符串数组们添加到结果数组的元素中去。
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
int sLen = s.size();
int pLen = p.size();
if(sLen < pLen){
return vector<int>();
}
vector<int> ans; // 结果 记录符合条件向量的起始索引
vector<int> sCount(26);
vector<int> pCount(26);
// 初始化滑动窗口
for(int i = 0; i < pLen; i++){
sCount[s[i] - 'a']++;
pCount[p[i] - 'a']++;
}
if(sCount == pCount){
ans.emplace_back(0);
}
// 移动滑动窗口
for(int i = 0; i < sLen - pLen; i++){
sCount[s[i] - 'a']--;
sCount[s[i + pLen] - 'a']++;
if(sCount == pCount){
ans.emplace_back(i + 1);
}
}
return ans;
}
};
note:用固定窗口大小的滑动窗口移动来依次判断子数组是不是另一个数组的有效异位词,判断的方式是通过数组进行26个英文字母的哈希映射。
3.两个数组的交集
代码:
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
// unordered_set自带去重
unordered_set<int> result_set;
unordered_set<int> nums_set(nums1.begin(),nums1.end());
for(int num:nums2){
// 判断nums2里的元素有没有在nums1的哈希映射的num_set里出现过
if(nums_set.find(num) != nums_set.end()){
result_set.insert(num);
}
}
return vector<int>(result_set.begin(),result_set.end());
}
};
note:把其中一个数组映射到哈希表里,然后遍历另一个数组,如果这个元素在哈希表里出现过就加到结果集里。这里的unordered_set帮助我们实现了去重。
相关题目练习
class Solution {
public:
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
if(nums1.size() > nums2.size()){
return intersect(nums2,nums1); // 确保nums1的长度更短
}
unordered_map<int,int> m;
for(int num:nums1){
m[num]++;
}
vector<int> intersection;
for(int num:nums2){
if(m.count(num)){
intersection.push_back(num);
m[num]--;
if(m[num] == 0){
m.erase(num);
}
}
}
return intersection;
}
};
note:
如果使用find函数来写
4.快乐数
代码:
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);
// 变为1
if(sum == 1){
return true;
}
// 无限循环
if(set.find(sum) != set.end()){
return false;
}else{
set.insert(sum);
}
n = sum;
}
}
};
note:两种情况,一种是在经历变换过程的时候为1,也就是快乐数;另一种是出现了无限循环小数,循环这个要素就用哈希表来判断了。
5.两数之和
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> map;
for(int i = 0; i < nums.size(); i++){
auto iter = map.find(target - nums[i]);
if(iter != map.end()){
return {iter->second,i};
}
map.insert(pair<int,int>(nums[i],i));
}
return {};
}
};
note:就是一道很典型的用map的题。一边遍历数组一边去看以及遍历过的部分对应的哈希表里有没有target-nums[i]。如果有就直接返回,如果没有就把此键值对加入哈希表中。