力扣100/49

57 阅读3分钟

LC49

49. 字母异位词分组 - 力扣(LeetCode)

给定一个字符串数组 strs,请你将所有是“字母异位词”的字符串组合在一起。最终结果可以按任意顺序返回

  1. 要对字母异位词进行分组,首先需要一个方法来“识别”它们。也就是说,需要找到一种方式,让所有字母异位词都拥有一个相同的“标识”或“签名”,而不同的字母异位词则拥有不同的标识
  2. 既然字母异位词只是字符排列顺序不同,那么它们共同的属性就是:所包含的字符种类和每种字符的数量是相同的

排序字符串 (Sorted String):

如果两个字符串是字母异位词,那么将它们各自的字符排序后,得到的字符串将是完全相同的

算法步骤:

  1. 创建一个哈希表 (std::unordered_map)
    1. 键 (Key): 用来识别字母异位词的“标识”,这里是排序后的字符串
    2. 值 (Value): 是一个字符串列表 (std::vector<std::string>),用于存储所有具有相同标识的原始字符串
  2. 遍历输入的字符串数组 strs 中的每个字符串 s
    1. s 复制一份,得到 key_s
    2. key_s 进行排序 (例如使用 std::sort
    3. 将原始字符串 s 添加到哈希表中以 key_s 为键对应的字符串列表中
  3. 遍历哈希表,将其所有值 (即每个字符串列表) 收集起来,形成最终的结果列表
class Solution {
public:
    std::vector<std::vector<std::string>> groupAnagrams(std::vector<std::string>& strs) {
        // 哈希表:键是排序后的字符串 (作为标识),值是原始字符串的列表
        std::unordered_map<std::string, std::vector<std::string>> anagram_groups;
        
        // 遍历输入的每个字符串
        for (const std::string& s : strs) {
            // 创建一个副本,用于排序作为键
            std::string key = s; 
            // 对副本进行排序,这将是字母异位词的唯一标识
            std::sort(key.begin(), key.end()); 
            
            // 将原始字符串添加到以排序后的字符串为键的列表中
            anagram_groups[key].push_back(s);
        }
        
        // 收集结果:将哈希表中所有值 (即每个组的字符串列表) 放入最终结果
        std::vector<std::vector<std::string>> result;
        for (auto const& [key, val] : anagram_groups) { // C++17 结构化绑定,方便遍历 map
            result.push_back(val);
        }
        
        return result;
    }
};

时间复杂度分析:

  1. 假设输入数组 strs 包含 N 个字符串
  2. 每个字符串的平均长度为 L
  3. 遍历 N 个字符串: O(N)
  4. 对每个字符串进行排序: std::sort 对长度为 L 的字符串排序的时间复杂度是 O(LlogL)
  5. 总的时间复杂度是 N 乘以单次操作的时间,即 O(N⋅LlogL)

空间复杂度分析:

  1. 哈希表 anagram_groups 最多会存储 N 个键值对 (每个字符串独立成组)
  2. 键是排序后的字符串,长度为 L。值是原始字符串的列表,总共存储了所有 N 个原始字符串,总长度为 N⋅L
  3. 空间复杂度是 O(N⋅L)