哈希表在Leetcode中的用法

作为一名初学者,掌握 unordered_map 的用法是刷算法题的关键一步,它能解决非常多的问题。总结 unordered_map 的核心用法,并清晰地解释 setmap 的区别以及它们各自的使用场景。


一、 unordered_map 哈希表的核心用法 (算法题利器)

你可以把 unordered_map 想象成一个**“超级字典”**。普通字典是“单词 -> 释义”,而 unordered_map 是“键 (Key) -> 值 (Value)”。

它的最大特点是:查找、插入、删除都非常快,平均时间复杂度为 O(1),也就是几乎不花时间。

核心操作
#include <iostream>
#include <string>
#include <unordered_map>

// 声明一个 `unordered_map`,键是字符串类型,值是整数类型
std::unordered_map<std::string, int> my_map;

// 1. 插入/更新键值对 (像查字典一样,没有就新增,有就更新)
my_map["apple"] = 10;   // 插入 "apple" -> 10
my_map["banana"] = 5;
my_map["apple"] = 12;   // 更新 "apple" -> 12

// 2. 访问值
std::cout << my_map["apple"]; // 输出 12

// 3. 检查一个键是否存在 (非常重要!)
if (my_map.count("banana")) { // .count(key) 返回 1 (存在) 或 0 (不存在)
    std::cout << "banana exists!";
}

// 4. 删除一个键值对
my_map.erase("banana");

// 5. 遍历哈希表 (C++17 语法,非常方便)
for (auto const& [key, val] : my_map) {
    std::cout << key << ": " << val << std::endl;
}
在算法题中的三大经典应用场景

场景 1:频率计数 (Counting Frequencies)

问题类型:统计数组/字符串中每个元素出现的次数、寻找出现次数最多的元素、判断两个字符串是否为字母异位词等。

这是 unordered_map 最最常见的用法。

  • Key: 数组中的元素或字符串中的字符。
  • Value: 该元素出现的次数。

示例:统计字符串中每个字符的出现次数

#include <string>
#include <unordered_map>

std::string s = "hello world";
std::unordered_map<char, int> freq_counter;

for (char c : s) {
    freq_counter[c]++; // 如果 c 不存在,会自动创建 c->0,然后++变为1;如果存在,直接++
}

// freq_counter['l'] 的值会是 3

场景 2:快速查找/建立“备忘录” (Fast Lookup / Seen Tracker)

问题类型两数之和 (Two Sum)、无重复字符的最长子串、判断数组中是否有重复元素等。

你需要快速知道“某个元素是否出现过”以及它的“相关信息”(比如下标)。

  • Key: 数组中的元素。
  • Value: 该元素的下标或其他需要记录的信息。

示例:两数之和 (LeetCode 第1题)

在数组 nums 中找两个数,使它们的和等于 target,返回它们的下标。

#include <vector>
#include <unordered_map>

vector<int> twoSum(vector<int>& nums, int target) {
    // Key: 数字, Value: 该数字的下标
    std::unordered_map<int, int> seen_map;
    for (int i = 0; i < nums.size(); ++i) {
        int complement = target - nums[i]; // 计算需要配对的另一个数
        if (seen_map.count(complement)) {   // 检查配对数是否在“备忘录”里
            return {seen_map[complement], i}; // 找到了!
        }
        seen_map[nums[i]] = i; // 没找到,就把当前数和它的下标存入“备忘录”
    }
    return {};
}

场景 3:缓存计算结果 (Caching / Memoization)

问题类型:斐波那契数列、爬楼梯等动态规划或递归问题,其中有很多重复计算。

用来存储已经计算过的子问题的解,避免重复劳动。

  • Key: 子问题的输入参数。
  • Value: 该子问题的计算结果。

二、 setmap 的区别

为了方便理解,我把它们分成两组:set 家族和 map 家族。

核心区别
特性set 家族 (unordered_set, set)map 家族 (unordered_map, map)
存储内容只存储单个元素 (Key)存储键值对 (Key-Value Pair)
核心目的判断一个元素是否存在,并保证所有元素唯一。根据一个 Key,存取一个与之关联的 Value。
生活中的比喻派对的宾客名单电话本
解决的问题“张三在名单上吗?”“张三的电话号码是多少?”

简单来说:

  • 当你只关心“一个东西在不在这里”,用 set
  • 当你关心“一个东西对应的信息是什么”,用 map
unordered_ vs. std:: (哈希 vs. 有序)

这是一个性能和功能上的取舍。

类型std::unordered_set<br>std::unordered_mapstd::set<br>std::map
内部实现哈希表红黑树 (一种自平衡二叉搜索树)
元素顺序无序的 (遍历时顺序不确定)有序的 (元素总是按键排序)
性能查找、插入、删除平均 O(1)查找、插入、删除 O(log N)
选择时机绝大多数算法题的首选,因为追求极致的速度。当你需要自动保持元素有序时才使用。

三、何时应该用?(给初学者的决策指南)

当你遇到一个问题时,可以这样问自己:

  1. 我需要存储“键值对”信息吗?(比如 数字->下标字符->次数
    • -> 进入 map 家族。
      • 我需要让这些键自动排序吗?
        • (99%的算法题) -> std::unordered_map (你的首选!)
        • -> std::map
    • 否,我只需要知道一个元素存不存在,或者需要一个不含重复元素的集合。 -> 进入 set 家族。
      • 我需要让这些元素自动排序吗?
        • (绝大多数情况) -> std::unordered_set (你的首选!)
        • -> std::set
总结:给初学者的黄金法则

在刷算法题时,如果你需要一个哈希结构,无脑先用 unordered_mapunordered_set。因为算法题通常最看重时间效率,O(1) 的性能优势是巨大的。只有当题目有明确要求(比如“按字母顺序输出所有独特的单词”)时,你才需要考虑使用有序的 mapset

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值