这几道哈希的题目,其用到的思想适用于很多可以用哈希来解决的题目。

383. 赎金信

题目

383. 赎金信

给你两个字符串:ransomNotemagazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。

如果可以,返回 true ;否则返回 false

magazine 中的每个字符只能在 ransomNote 中使用一次。

1
2
3
4
5
6
7
8
9
10
11
示例 1:
输入:ransomNote = "a", magazine = "b"
输出:false

示例 2:
输入:ransomNote = "aa", magazine = "ab"
输出:false

示例 3:
输入:ransomNote = "aa", magazine = "aab"
输出:true
  • 1 <= ransomNote.length, magazine.length <= 105
  • ransomNotemagazine 由小写英文字母组成

思路和代码

因为给出的两个字符串里面都只包含小写的英文字母,所以我们用不上unordered_map,只需要用一个26长度的int数组就可以了。

  • 26长度的int数组,全部初始化为0;
  • 遍历,记录magazine中每一个字符出现的次数;
  • 遍历ransomNote字符串,将magazine中对应字符计数器减一;
  • 如果某个计数器减至负数,则说明magazine中的字符不够用,返回false;
  • 如果遍历完毕没有出现问题,则返回true;

代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
if(ransomNote.size() > magazine.size()){
return false; // 因为已经超过了字符大小,所以肯定不符合条件
}
int arr[26] = {0};
for(int i = 0;i<magazine.size();i++){
arr[magazine[i] -'a'] ++;
}
for(int i = 0;i<ransomNote.size();i++){
arr[ransomNote[i] -'a'] --;
if(arr[ransomNote[i] -'a'] < 0){
return false;
}
}
return true;
}
};

image-20240318180705925

202. 快乐数

题目

202. 快乐数

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

  • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
  • 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
  • 如果这个过程 结果为 1,那么这个数就是快乐数。

如果 n快乐数 就返回 true ;不是,则返回 false

1
2
3
4
5
6
7
8
9
10
11
12
示例 1:
输入:n = 19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1

示例 2:
输入:n = 2
输出:false
  • 1 <= n <= 231 - 1

思路

这道题其实是个数学题,用到哈希的地方是判断之前出现的结果是否已经出现过了。题目中提到“然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1”,即可能会有用例,到最后计算的结果出现无限循环。

此时就需要用哈希来判断某一个结果是否已经出现过,如果出现过,第二次出现的时候就说明重复了,返回false退出循环计算即可。

代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
// 每一次的计算
int getSum(int n)
{
int sum = 0; // 这里必须赋值为0
while(n > 0)
{
sum += (n%10)*(n%10);
n/=10;
}
return sum;
}
public:
bool isHappy(int n) {
unordered_set<int> sets;
int sum = 0;
while(1)
{
sum = getSum(n);
cout << sum << endl;
if(sum == 1){ // 符合题目条件
return true;
}
if(sets.count(sum) != 0){
return false; // 出现重复了
}
sets.insert(sum);
n = sum;
}
return false;
}
};

image-20240318181637436

242. 有效的字母异位词

题目

242. 有效的字母异位词

给定两个字符串 *s**t* ,编写一个函数来判断 *t* 是否是 *s* 的字母异位词。

注意:*s**t* 中每个字符出现的次数都相同,则称 *s**t* 互为字母异位词。

示例 1:

1
2
输入: s = "anagram", t = "nagaram"
输出: true

示例 2:

1
2
输入: s = "rat", t = "car"
输出: false

提示:

  • 1 <= s.length, t.length <= 5 * 104
  • st 仅包含小写字母

思路

字母异位词就是两个字符串中所有字符出现的次数都相同,如果有不同的就不是字母异位词。

可以用两种思路来解决

  • 对字符串排序,字母异位词排序后的结果肯定相同
  • 使用哈希计算每个字符出现的次数,比较两个字符串中每个字符出现的次数是否相同,不相同则出现错误

这里采用哈希的思路,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Solution {
public:
bool isAnagram(string s, string t) {
unordered_map<char,int> maps;
for(auto&e:s)
{
if(!maps.count(e))
{
maps[e] = 1;
}
else
{
maps[e]++;
}
}

for(auto&e:t)
{
if(!maps.count(e)){
return false;
}
maps[e]--;
}

for(auto&e:maps)
{
if(e.second != 0)
{
return false;
}
}
return true;
}
};

image-20240318181945788