leetcode 面试经典 150 题:字母异位词分组

链接 字母异位词分组
题序号 49
题型 字符串
解题方法 哈希表
难度 中等
熟练度 ✅✅✅

题目

  • 给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。

  • 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。

  • 示例 1:

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

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

  • 示例 2:

    输入: strs = [""]

    输出: [[""]]

  • 示例 3:

    输入: strs = ["a"]

    输出: [["a"]]

  • 提示:

    1 <= strs.length <= 10^4

    0 <= strs[i].length <= 100

    strs[i] 仅包含小写字母

题解

  1. 核心思想
    • 定义哈希表:使用 unordered_map 来存储每个字母异位词组。键是排序后的字符串,值是一个包含所有字母异位词的 vector。
    • 遍历字符串数组
      对于每个字符串,首先将其复制到一个临时字符串 key 中。
      对 key 进行排序,这样所有字母异位词的排序结果将相同,从而可以用作哈希表的键。
    • 插入哈希表
      将原始字符串插入到哈希表中,键为排序后的 key。这样,所有字母异位词都会被插入到同一个键对应的值(即 vector)中。
  2. 复杂度:时间复杂度O( n * k ),其中 n 是字符串数组的长度,k 是字符串的最大长度。每个字符串的字符计数需要 O(k) 的时间。空间复杂度:O( n * k ),主要是哈希表存储的空间。
  3. c++ 实现算法
cpp 复制代码
vector<vector<string>> groupAnagrams(vector<string>& strs) {
    
    unordered_map<string, vector<string>> hashTable; // 定义哈希表

    //遍历输入的字符串数组
    for (const string& str : strs) {

        string key = str; //将当前字符串赋值给 key
        
        sort(key.begin(), key.end()); // 将字符串排序,作为哈希表的键
        
        // 将原始字符串 str 插入到哈希表中,键为排序后的 key
        //在 vector<string> 类型的值末尾添加一个新的元素(str),vector 是个动态数组
        hashTable[key].push_back(str); 
    }

    vector<vector<string>> result; // 存储最终结果

    for (auto& entry : hashTable) {
         // 遍历哈希表,将每个键对应的值(即一个字母异位词的分组)插入到结果数组中
        result.push_back(entry.second); 
    }

    return result;
}
  1. 算法推演
  • 输入数据:
    假设输入是以下字符串数组: vector strs = {"eat", "tea", "tan", "ate", "nat", "bat"};
  1. 初始化:

    首先,定义一个空的哈希表: unordered_map<string, vector> hashTable;

  2. 遍历输入字符串并构建哈希表:

    我们开始遍历 strs 数组,每次拿到一个字符串,然后对其进行处理。

  • 第一轮:

    处理字符串 "eat"

    "eat" 赋值给key。

    对 key 排序,得到 "aet"。

    在哈希表中查找 "aet",发现没有,所以自动创建新的键值对:hashTable["aet"] = ["eat"]。

    哈希表此时是: hashTable =

    {

    "aet": ["eat"]

    };

  • 第二轮:

    处理字符串 "tea"

    "tea" 赋值给key。

    对 key 排序,得到 "aet"。

    查找哈希表,发现 "aet" 已经存在,直接将 "tea" 加入对应的 vector:hashTable["aet"].push_back("tea")。

    哈希表此时是:hashTable =

    {

    "aet": ["eat", "tea"]

    };

  • 第三轮:

    处理字符串 "tan"

    "tan" 赋值给 key。

    对 key 排序,得到 "ant"。

    查找哈希表,发现 "ant" 不存在,自动创建新的键值对:hashTable["ant"] = ["tan"]。

    哈希表此时是: hashTable =

    {

    "aet": ["eat", "tea"],

    "ant": ["tan"]

    };

  • 第四轮:

    处理字符串 "ate"

    "ate" 赋值给 key。

    对 key 排序,得到 "aet"。

    查找哈希表,发现 "aet" 已经存在,直接将 "ate" 加入对应的 vector:hashTable["aet"].push_back("ate")。

    哈希表此时是:

    hashTable =

    {

    "aet": ["eat", "tea", "ate"],

    "ant": ["tan"]

    };

  • 第五轮:

    处理字符串 "nat"

    "nat" 赋值给 key。

    对 key 排序,得到 "ant"。

    查找哈希表,发现 "ant" 已经存在,直接将 "nat" 加入对应的 vector:hashTable["ant"].push_back("nat")。

    哈希表此时是:

    hashTable =

    {

    "aet": ["eat", "tea", "ate"],

    "ant": ["tan", "nat"]

    };

  • 第六轮:

    处理字符串 "bat"

    "bat" 赋值给 key。

    对 key 排序,得到 "abt"。

    查找哈希表,发现 "abt" 不存在,自动创建新的键值对:hashTable["abt"] = ["bat"]。

    哈希表此时是: hashTable =

    {

    "aet": ["eat", "tea", "ate"],

    "ant": ["tan", "nat"],

    "abt": ["bat"]

    };

  1. 构建结果: 接下来,我们遍历哈希表,将每组异位词添加到结果 result 中。
    vector<vector> result; for (auto& entry : hashTable) {
    result.push_back(entry.second); // 将每组异位词加入结果
    }
  • 遍历哈希表:

    第一组:

    entry.first = "aet", entry.second = ["eat", "tea", "ate"]。

    将 ["eat", "tea", "ate"] 添加到 result 中。

    第二组:

    entry.first = "ant", entry.second = ["tan", "nat"]。

    将 ["tan", "nat"] 添加到 result 中。

    第三组:

    entry.first = "abt", entry.second = ["bat"]。

    将 ["bat"] 添加到 result 中。

  • 最终 result 是: result =

    {

    {"eat", "tea", "ate"},

    {"tan", "nat"},

    {"bat"}

    };

  1. 返回结果: 函数返回 result,即字母异位词的分组。
  1. c++ 完整demo
cpp 复制代码
#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <algorithm>

using namespace std;

vector<vector<string>> groupAnagrams(vector<string>& strs) {
    
    unordered_map<string, vector<string>> hashTable; // 定义哈希表

    //遍历输入的字符串数组
    for (const string& str : strs) {

        string key = str; //将当前字符串赋值给 key
        
        sort(key.begin(), key.end()); // 将字符串排序,作为哈希表的键
        
        // 将原始字符串 str 插入到哈希表中,键为排序后的 key
        //在 vector<string> 类型的值末尾添加一个新的元素(str),vector 是个动态数组
        hashTable[key].push_back(str); 
    }

    vector<vector<string>> result; // 存储最终结果

    for (auto& entry : hashTable) {

        result.push_back(entry.second); // 遍历哈希表,将每个键对应的值(即一个字母异位词的分组)插入到结果数组中
    }

    return result;
}

int main() {
    vector<string> strs = {"eat", "tea", "tan", "ate", "nat", "bat"};
    vector<vector<string>> result = groupAnagrams(strs);

    for (const auto& group : result) {
        for (const auto& word : group) {
            cout << word << " ";
        }
        cout << endl;
    }

    return 0;
}
相关推荐
爱学习的茄子16 分钟前
JavaScript事件循环深度解析:理解异步执行的本质
前端·javascript·面试
是白可可呀2 小时前
LeetCode 169. 多数元素
leetcode
jz_ddk2 小时前
[实战]调频(FM)和调幅(AM)信号生成(完整C语言实现)
c语言·算法·信号处理
Tipriest_2 小时前
[数据结构与算法] 优先队列 | 最小堆 C++
c++·优先队列·数据结构与算法·最小堆
DoraBigHead2 小时前
🧠 别急着传!大文件上传里,藏着 Promise 的高级用法
前端·javascript·面试
CloudAce云一2 小时前
谷歌云代理商:谷歌云TPU/GPU如何加速您的AI模型训练和推理
算法
爱学习的茄子2 小时前
JavaScript闭包应用场景完全指南:从基础概念到工程实践
前端·javascript·面试
轻语呢喃3 小时前
每日LeetCode : 杨辉三角
javascript·后端·算法
YuTaoShao3 小时前
【LeetCode 热题 100】148. 排序链表——(解法二)分治
java·算法·leetcode·链表
Shilong Wang3 小时前
三维旋转沿轴分解
算法·计算机视觉·机器人