【算法日记 13】LeetCode 49. 字母异位词分组:哈希表的进阶“降维打击”

🚀【算法日记】LeetCode 49. 字母异位词分组:哈希表的进阶"降维打击"

📍 题目背景

今天咱们来手撕一道 LeetCode 上的经典中等难度大题,同时也是大厂面试中极高频的常客:49. 字母异位词分组 。 这道题不仅考察了我们对字符串的处理能力,更是对 哈希表 (Hash Map) 进阶运用的完美测验。

【题目描述】 给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词:由重新排列源单词的所有字母得到的一个新单词(即字母相同,但排列顺序不同)。

【示例】

输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]

输出: [["bat"], ["nat","tan"], ["ate","eat","tea"]]

✨ 核心破题逻辑:寻找"共有 DNA"

这道题最大的难点在于:计算机怎么知道 "eat""tea" 是同一伙人?

如果暴力去统计每个字符出现的次数然后对比,代码会写得非常冗长且容易出错。 在这里,我们需要用到算法中极其优雅的"降维打击"思维:找它们的共有特征(DNA)!

既然"字母异位词"只是把相同的字母打乱了顺序,那么只要我们把它们重新按字母表顺序排好,它们不就长得一模一样了吗?

  • "eat" 排序后变成 "aet"

  • "tea" 排序后变成 "aet"

  • "bat" 排序后变成 "abt"

破题三步曲:

  1. 准备一个超级大抽屉柜(unordered_map)。

  2. 抽屉的标签(Key )贴上排序后的词(比如 "aet")。

  3. 抽屉里面(Value)放一个数组,把所有排序后等于这个标签的"原词"全扔进去!

遍历完整个数组后,把所有抽屉里的数组打包提取出来,就是我们要的最终答案!

💻 C++ 满分 AC 代码

这份代码极其精简,并且融入了 C++11 的 auto 特性,写起来非常丝滑。

复制代码
#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <algorithm>

using namespace std;

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        // 核心数据结构:Key 是排序后的字符串,Value 是原始字符串构成的数组
        unordered_map<string, vector<string>> mp;
        
        // 1. 遍历所有字符串
        // 🌟 细节优化:使用 const auto& 避免字符串的无意义拷贝,提升速度!
        for(const auto& str : strs) {
            string key = str; // 拿出一个字符串,复制一份当做钥匙
            
            // 2. 找到异位词的"共有DNA":对钥匙进行排序
            sort(key.begin(), key.end());
            
            // 3. 把原始字符串塞进对应钥匙的抽屉里
            mp[key].push_back(str);
        }
        
        // 4. 把所有抽屉里的分组打包带走
        vector<vector<string>> res;
        for(auto it = mp.begin(); it != mp.end(); ++it) {
            res.push_back(it->second); // it->second 就是装满异位词的 vector
        }
        
        return res;
    }
};

🔍 深度解析与避坑指南

1. 为什么用 unordered_map 而不是 map

在 C++ 中,map 的底层是红黑树(有序),而 unordered_map 的底层是哈希表(无序)。既然题目要求"可以按任意顺序返回",我们完全不需要对 Key 进行额外的排序,直接使用 unordered_map 可以获得 O(1) 的超快查找速度!

2. 代码细节优化:const auto&

for(const auto& str : strs) 这一行中:

  • 如果只写 auto str,每次循环都会把原字符串完整复制一遍,极度消耗性能。

  • 加上 &(引用)直接操作原内存,加上 const(常量)保证不会意外修改原数据。这是大厂面试官非常看重的 C++ 编码好习惯!

3. 复杂度分析

  • 时间复杂度: O(N \\times K \\log K)。其中 N 是字符串数组的长度,K 是数组中字符串的最大长度。遍历数组需要 O(N),对每个字符串排序需要 O(K \\log K)

  • 空间复杂度: O(N \\times K)。我们需要用哈希表存储所有的字符串。

💡 总结: 这道题完美诠释了"数据预处理(排序) + 哈希表分组"的黄金组合。掌握了这个套路,以后遇到类似的"分类归纳"问题,都能做到秒杀!

相关推荐
KaMeidebaby1 小时前
卡梅德生物技术快报|纳米抗体技术全套实操流程:AFB1 全合成文库淘选 + 分子对接定点突变参数手册
人工智能·python·tcp/ip·算法·机器学习
2601_962851742 小时前
计算机毕业设计之基于YOLOV10的低光照目标检测算法研究与实现
大数据·算法·yolo·目标检测·信息可视化·cnn·课程设计
magicwt2 小时前
快手自动出价论文GAVE阅读笔记
算法
智者知已应修善业2 小时前
【P12159蓝桥杯数组翻转】2025-4-24
c语言·c++·经验分享·笔记·算法·蓝桥杯
小巧的砖头3 小时前
使用SVN+CruiseControl+ANT实现持续集成之一
学习·算法
人道领域3 小时前
【LeetCode刷题日记】贪心算法理论与实战:455.分发饼干最优解
java·开发语言·数据结构·算法·leetcode·贪心算法
小O的算法实验室3 小时前
2026年ACM TCH,动态救护车路径优化:结合 K-means 聚类与多目标粒子群算法两阶段策略
算法
在书中成长3 小时前
HarmonyOS 小游戏《对战五子棋》开发第8篇 - GomokuEngine核心引擎设计(三):五子连珠判定算法
算法·华为·harmonyos
Let's Chat Coding4 小时前
MAC 消息认证码:同时验证来源和完整性
算法·哈希算法