1. 题目
题目描述
给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。
如果可以,返回 true ;否则返回 false。
magazine 中的每个字符只能在 ransomNote 中使用一次。
示例
输入:ransomNote = "a", magazine = "b"
输出:false
输入:ransomNote = "aa", magazine = "ab"
输出:false
输入:ransomNote = "aa", magazine = "aab"
输出:true
约束
-
(1 <= ransomNote.length, magazine.length <= 10^5)
-
两个字符串均由小写英文字母组成
2. 最佳解题思路描述(字母计数数组,最优)
-
只有 26 个小写字母,开辟长度 26 的数组统计字符出现次数;
-
先遍历
magazine,对应字母位置计数 + 1; -
再遍历
ransomNote,对应字母位置计数 - 1; -
最后遍历计数数组,若存在任意位置数值小于 0,说明赎金信需要的字符数量多于杂志拥有,返回 false;全部≥0 则返回 true。
优势
-
时间复杂度 (O(m+n)),m、n 为两个字符串长度,仅两次遍历;
-
空间复杂度 (O(1)),固定长度 26 数组,常数空间;
-
相比哈希表
unordered_map,数组寻址更快、无哈希冲突开销,本题首选。
3. 可优化代码(逻辑完全标准最优,仅微小格式优化)
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int Arr[26] = {0};
for(char c : magazine){
Arr[c-'a']++;
}
for(char c : ransomNote){
Arr[c-'a']--;
}
for(int i : Arr){
if(i<0){
return false;
}
}
return true;
}
};
代码说明
-
正确性:无任何逻辑 bug,能通过全部测试用例,是本题标准最优解法;
-
细微优化点(不影响 AC,仅提升规范度):
-
数组名
Arr语义模糊,改为cnt/count更易懂; -
可在遍历赎金信时提前判断,计数减为 0 直接返回 false,省去最后一轮完整遍历;
-
变量、循环增加空格,代码可读性更好。
-
4. 规范优化版(提前终止,减少一轮遍历)
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int cnt[26] = {0};
// 统计杂志字符
for (char c : magazine) {
cnt[c - 'a']++;
}
// 匹配赎金信,中途不足直接返回false
for (char c : ransomNote) {
int idx = c - 'a';
cnt[idx]--;
if (cnt[idx] < 0) {
return false;
}
}
return true;
}
};
5. 总结
-
数组计数思路完全正确、性能最优;
-
核心逻辑:杂志字符做加法,赎金信字符做减法,负数代表字符不够;
-
26 个小写字母固定场景,优先用数组而非哈希表;
-
优化小技巧:遍历赎金信时实时判断,提前 return,不用完整遍历 26 个数字。
6. 相关知识拓展
拓展 1:哈希表写法(不推荐,开销更大)
字符种类少时数组完胜哈希,仅字符范围大时选用:
#include <unordered_map>
bool canConstruct(string ransomNote, string magazine) {
unordered_map<char, int> mp;
for (char c : magazine) mp[c]++;
for (char c : ransomNote) {
mp[c]--;
if (mp[c] < 0) return false;
}
return true;
}
拓展 2:同类字符计数模板题
-
LC242 有效的字母异位词(同样 26 数组统计,最终全部为 0)
-
LC438 找到字符串中所有字母异位词(滑动窗口 + 26 计数数组)
-
LC125 验证回文串(字符筛选 + 计数)
拓展 3:复杂度对比
-
26 计数数组(优化后):(O(m+n)) 时间,(O(1)) 空间(最优);
-
unordered_map 哈希表:(O(m+n)) 时间,(O(1)) 理论空间,但常数开销更大;
拓展 4:易错点复盘
-
颠倒遍历顺序:先遍历 ransomNote 再加 magazine,逻辑完全颠倒;
-
忘记判断
<0,只判断等于 0,无法识别字符数量不足; -
使用大写 / 混合字符时未做范围判断(本题限定全小写无需处理)。