前言:这道题目是我第一道hot100,加油,冲冲冲!
题目解析
字母异位词(Anagram)是指由相同字母以不同顺序组成的单词。例如 "eat"、"tea"、"ate" 都包含字母 e、a、t,只是排列顺序不同。
题目要求我们将字符串数组中的所有字母异位词分组,每组包含所有互为异位词的字符串。
解题思路
核心思想:标准化键值
要判断两个字符串是否为字母异位词,最直接的方法是:
- 将两个字符串的字符按相同规则排序
- 如果排序后的结果相同,则它们是异位词
因此,我们可以将排序后的字符串作为哈希表的键,原始字符串作为值存储在对应的列表中。
算法步骤
-
创建一个哈希表,键为排序后的字符串,值为字符串列表
-
遍历输入数组中的每个字符串:
- 对当前字符串进行排序,得到标准化的键
- 将原始字符串添加到对应键的列表中
-
遍历哈希表,将所有值(字符串列表)收集到结果数组中
代码实现
cpp
编辑
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
// 使用哈希表存储分组结果
// key: 排序后的字符串,value: 原始字符串列表
unordered_map<string, vector<string>> anagramGroups;
// 遍历每个字符串
for (string s : strs) {
string key = s;
// 对字符串排序,得到标准化的键
sort(key.begin(), key.end());
// 将原始字符串添加到对应分组
anagramGroups[key].push_back(s);
}
// 收集所有分组结果
vector<vector<string>> result;
for (auto& pair : anagramGroups) {
result.push_back(pair.second);
}
return result;
}
};
算法复杂度分析
时间复杂度:O(N × M log M)
- N 是字符串数组的长度
- M 是字符串的平均长度
- 对每个字符串排序需要 O(M log M) 时间
- 总共需要处理 N 个字符串
空间复杂度:O(N × M)
- 哈希表需要存储所有字符串
- 每个字符串在哈希表中存储一次
优化方案:计数法替代排序
对于只包含小写字母的字符串,我们可以使用字符计数来替代排序,进一步优化性能。
cpp
编辑
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
unordered_map<string, vector<string>> anagramGroups;
for (string& s : strs) {
// 创建字符计数数组
vector<int> count(26, 0);
for (char c : s) {
count[c - 'a']++;
}
// 将计数数组转换为字符串作为键
string key = "";
for (int i = 0; i < 26; i++) {
if (count[i] > 0) {
key += string(1, 'a' + i) + to_string(count[i]);
}
}
anagramGroups[key].push_back(s);
}
vector<vector<string>> result;
for (auto& pair : anagramGroups) {
result.push_back(pair.second);
}
return result;
}
};
计数法的时间复杂度:O(N × M)
- 遍历每个字符串的每个字符:O(M)
- 构建键值:O(26) = O(1)
- 总体:O(N × M)
测试用例验证
示例 1
text
编辑
输入: ["eat", "tea", "tan", "ate", "nat", "bat"]
处理过程:
- "eat" → 排序 → "aet" → 分组["eat"]
- "tea" → 排序 → "aet" → 分组["eat", "tea"]
- "tan" → 排序 → "ant" → 分组["tan"]
- "ate" → 排序 → "aet" → 分组["eat", "tea", "ate"]
- "nat" → 排序 → "ant" → 分组["tan", "nat"]
- "bat" → 排序 → "abt" → 分组["bat"]
输出: [["bat"], ["nat","tan"], ["ate","eat","tea"]]
示例 2 & 3
- 空字符串排序后仍为空字符串
- 单字符字符串排序后不变
实际应用场景
- 文本处理:在文档分析中识别同义词或变体词
- 密码学:检测简单的字母替换密码
- 数据清洗:合并重复但拼写顺序不同的数据项
- 游戏开发:单词游戏中的字母组合验证
总结
这道题目完美展示了哈希表与标准化处理的结合威力:
- 标准化是关键:通过排序将异位词映射到相同的键
- 哈希表高效分组:O(1) 的平均查找时间确保高效分组
- 灵活优化:根据输入特征选择排序或计数法
掌握这种"标准化 + 哈希分组"的思维模式,可以解决许多类似的分组问题,如按质因数分组、按数字和分组等。这是算法面试中的经典套路,值得深入理解和熟练掌握。一天6道力扣,大厂等着你!