跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

LeetCode Hot 100 哈希表经典题目解析

综述由AI生成LeetCode Hot 100 中基于哈希表的三道经典题目:两数之和、字母异位词分组及最长连续序列。通过 unordered_map 和 unordered_set 优化查找效率,将时间复杂度从 O(n^2) 降低至 O(n)。详细讲解了哈希表在存储元素下标、键值映射及去重计数中的应用场景,并提供了完整的 C++ 代码实现及输入输出处理逻辑,适合算法初学者掌握哈希数据结构的核心用法。

RefactorPro发布于 2026/3/30更新于 2026/5/2324 浏览

1. 两数之和

思路与解法

当遍历到某一元素时,比如 3,当要求两数之和为 9 时,需要看 6 在之前有没有出现过,也就是某元素是否出现在这个集合中,那么我们就应该想到使用哈希法了。

因为本题我们不仅要知道元素有没有遍历过,还要知道这个元素对应的下标,需要使用 key、value 结构来存放,key 来存元素,value 来存下标,那么使用 map 正合适。

这道题目中并不需要 key 有序,选择 std::unordered_map 效率更高!

Map 的目的:

是用来存放我们访问过的元素,因为遍历数组的时候,需要记录我们之前遍历过哪些元素和对应的下标,这样才能找到与当前元素相匹配的(即相加等于 target)。

Map 中 key 和 value 分别表示什么:

在 map 里:

  • key:键,用来查找,本题为元素的值
  • value:值,表示这个键对应的数据,本题为元素对应的索引

这道题我们需要给出一个元素,判断这个元素是否出现过,如果出现过,返回这个元素的下标。

那么判断元素是否出现,这个元素的值就作为 key,因为 map 的作用是最快地查找 key 是否在 map 中出现过。所以数组中的元素作为 key,有 key 对应的就是 value,value 用来存下标。所以 map 中的存储结构为 {key: 数据元素,value: 数组元素对应的下标}。

在遍历数组的时候,只需要向 map 去查询是否有和目前遍历元素匹配的数值,如果有,就找到了匹配对,如果没有,就把目前遍历的元素放进 map 中,因为 map 存放的就是我们访问过的元素。

整体思路:定义 unordered_map——寻找,找到返回,未找到就添加——最终没有匹配的返回空!

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> map;
        for (int i = 0; i < nums.size(); i++) {
            auto it = map.find(target - nums[i]);
            if (it != map.end()) {
                return {it->second, i};
            }
            map.insert({nums[i], i});
        }
        return {};
    }
};

【注】

  1. map.find(…):unordered_map 的成员函数,用于查找指定的键。参数是要查找的键(key),返回一个迭代器(pair<const Key, Value> 类型)。
  2. unordered_map 是一个键值对(key-value pair)容器,它存储的元素实际上是 pair<const Key, Value> 类型的对象。用 map.insert({nums[i], i}) 更简洁!!
  3. 如果代码开头有 using namespace std,则不需要加 std::,leetcode 平台模板通常包含 using namespace std。
  4. 为何 return {iter->second, i}?因为要求返回的是满足条件的两个元素的数组下标,即 value。iter->first 访问的是 pair<const Key, Value> 中的 Key 部分,存放数组中的元素值;iter->second 访问的是 pair<const Key, Value> 中的 Value 部分,存放索引。

map.insert({nums[i], i}); 添加时是将当前元素的键值加入!!

完整代码示例
#include<bits/stdc++.h>
using namespace std;

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> map;
        for (int i = 0; i < nums.size(); i++) {
            auto it = map.find(target - nums[i]);
            if (it != map.end()) {
                return {it->second, i};
            }
            map.insert({nums[i], i});
        }
        return {};
    }
};

int main() {
    int n, target;
    cin >> n >> target;
    vector<int> nums(n);
    for (int i = 0; i < n; i++) {
        cin >> nums[i];
    }
    Solution solution;
    vector<int> result = solution.twoSum(nums, target);
    cout << result[0] << " " << result[1] << endl;
    return 0;
}

2. 字母异位词分组

思路及解法

字母异位词的特点是,它们的字母组成相同,只是排列顺序不同。 因此,可以通过对每个字符串进行排序(按从小到大的顺序排列),将排序后的字符串作为键,将原始字符串作为值存入哈希表中。最后,将哈希表中的值提取出来,即为分组后的结果。

核心代码:

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        unordered_map<string, vector<string>> map;
        for (string& str : strs) {
            string key = str; // 复制一个 key 出来再排序,避免影响原字符串
            sort(key.begin(), key.end());
            map[key].push_back(str);
        }
        vector<vector<string>> result;
        for (auto it = map.begin(); it != map.end(); it++) {
            result.push_back(it->second); // 将哈希 map 的值输出即为结果
        }
        return result;
    }
};

思路:定义哈希 map——取输入的每个字符串,复制后排序作为键,原字符串作为值存入哈希 map——从哈希 map 中取值即为结果

【注】

  1. 这里都是 string。别写成 int 了!! 哈希 map 例子:mp["aet"] = ["eat", "tea", "ate"] 键 aet(string 类型)对应的值为 "eat", "tea", "ate"(vector<string> 类型) 因此 map 为 <string, vector<string>> 类型
  2. operator[] 会自动创建默认值
  3. emplace_back 是 C++ 容器里的一个尾部插入函数,是把构造对象需要的参数直接传进去,让容器在尾部原地构造。 和 push_back 的区别:push_back 是把一个已经存在的对象塞进去。 什么情况下 emplace_back 更有优势?当元素类型比较复杂时,更明显。
完整代码示例
#include<bits/stdc++.h>
using namespace std;

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        unordered_map<string, vector<string>> map;
        for (string& str : strs) {
            string key = str;
            sort(key.begin(), key.end());
            map[key].push_back(str);
        }
        vector<vector<string>> result;
        for (auto it = map.begin(); it != map.end(); it++) {
            result.push_back(it->second);
        }
        return result;
    }
};

int main() {
    int n;
    cin >> n;
    vector<string> str(n);
    for (int i = 0; i < n; i++) {
        cin >> str[i];
    }
    Solution solution;
    vector<vector<string>> result = solution.groupAnagrams(str);
    for (auto i : result) {
        for (auto j : i) {
            cout << j << " ";
        }
        cout << endl;
    }
    return 0;
}

3. 最长连续序列

思路与解法

核心思想就两步:

  1. 先把所有数字放进哈希集合 unordered_set(会自动去重)
  2. 判断哈希集合中 num - 1 是否存在,不存在说明 num 是一个起点(一定要从起点开始!!),然后不断查 num + 1、num + 2、num + 3 是否存在,统计这一段连续长度

核心代码:

class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        if (nums.empty()) return 0;
        unordered_set<int> set(nums.begin(), nums.end());
        int longestLength = 0;
        for (int n : nums) {
            if (set.find(n - 1) == set.end()) {
                int currentNum = n;
                int currentLength = 1;
                while (set.find(currentNum + 1) != set.end()) {
                    currentNum++;
                    currentLength++;
                }
                longestLength = longestLength < currentLength ? currentLength : longestLength;
            }
        }
        return longestLength;
    }
};

【注】

  1. longestLength = longestLength < currentLength ? currentLength : longestLength; 要写在 if(set.find(n-1)==set.end()){} 循环里
完整代码示例
#include<iostream>
#include<unordered_set>
#include<vector>
using namespace std;

class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        if (nums.empty()) return 0;
        unordered_set<int> set(nums.begin(), nums.end());
        int longestLength = 0;
        for (int n : set) {
            if (set.find(n - 1) == set.end()) {
                int currentNum = n;
                int currentLength = 1;
                while (set.find(currentNum + 1) != set.end()) {
                    currentNum++;
                    currentLength++;
                }
                longestLength = longestLength < currentLength ? currentLength : longestLength;
            }
        }
        return longestLength;
    }
};

int main() {
    int n;
    cin >> n;
    vector<int> res(n);
    for (int i = 0; i < n; i++) {
        cin >> res[i];
    }
    Solution solution;
    cout << solution.longestConsecutive(res) << endl;
    return 0;
}

【注】

  1. for(int n : set){ 注意是从 set 中取!!!

目录

  1. 1. 两数之和
  2. 思路与解法
  3. Map 的目的:
  4. Map 中 key 和 value 分别表示什么:
  5. 完整代码示例
  6. 2. 字母异位词分组
  7. 思路及解法
  8. 完整代码示例
  9. 3. 最长连续序列
  10. 思路与解法
  11. 完整代码示例
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Docker Compose 部署 MySQL 8.4 LTS 生产环境指南
  • C++ 函数重载:核心规则、常见陷阱与实战
  • Apache IoTDB 产品介绍与 Kubernetes 1.24 集群安装部署
  • VSCode 集成 DeepSeek 模型配置与使用指南
  • Javashop 商城系统:企业级电商解决方案架构解析
  • Llama 3.1 大模型云端部署实践与体验
  • Spring AI 工具调用(Tool Calling)详解
  • 解决 Java 源发行版 17 与目标发行版不匹配问题
  • Java 后端实习复盘:企业级项目实战与核心代码解析
  • PTA L2-054 三点共线 C++ 题解与易错坑点分析
  • Microsoft Edge WebView2 Runtime 运行库快速部署与调试指南
  • Code Llama 7B 模型完整使用指南
  • GitHub Copilot 三种模式详解:Ask、Agent、Edit
  • Realistic Vision V2.0 超写实 AI 绘画使用指南
  • C++26 CPU 亲和性底层机制与性能优化实践
  • Hunyuan-MT-7B-WEBUI 部署与多语言翻译实测
  • 基于无人机的6G网络安全性分析与挑战
  • C++ RTTI 与多态机制深度解析:原理、开销与实践
  • DigitalOcean 云主机注册与创建指南
  • Qwen2.5 思维链微调实战:多卡 LoRA 完整代码示例

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online