百度C++一面:map和unordered_map相关面试题 + 力扣49. 字母异位词分组(可优化)

百度C++一面:map和unordered_map相关面试题百度C++一面:map和unordered_map相关面试题

本文整理自百度 C++ 一面高频面试题,覆盖底层原理、性能对比、迭代器失效、扩容机制、线程安全等核心考点,建议收藏。

目录


一、底层实现

特性 map unordered_map
底层数据结构 红黑树(自平衡二叉搜索树) 哈希表(散列表)
存储结构 树节点,按 key 大小有序排列 桶数组 + 开链法(链表挂桶)

二、性能对比

操作 map unordered_map
插入 O(log n),稳定 平均 O(1),最坏 O(n)
查找 O(log n),稳定 平均 O(1),最坏 O(n)
删除 O(log n),稳定 平均 O(1),最坏 O(n)

unordered_map 退化为 O(n) 的场景:

  • 哈希函数质量差,大量 key 碰撞到同一个桶
  • 故意构造的对抗性数据(哈希碰撞攻击)
  • 极端情况下所有元素挤在一条链上,退化为链表遍历

三、有序性

map 有序:红黑树本质是二叉搜索树,中序遍历结果即 key 从小到大的有序序列。

unordered_map 无序

  • 元素存储位置由 hash(key) % 桶数量 决定,与 key 大小无关
  • 不同 key 的哈希值分布"随机",桶的下标也是"乱"的
  • 扩容 rehash 后,元素位置会变化,遍历顺序可能前后不一致

💡 注意:unordered_map 的遍历有确定顺序(桶序 + 桶内链表序),但这不是"有序",只是存储顺序。


四、哈希冲突解决

STL unordered_map 采用开链法(链地址法)。

方法 原理 优点 缺点
开链法 每个桶挂一条链表,冲突元素追加到链上 删除简单;负载因子可超过 1 指针开销;缓存不友好
开放寻址 冲突时按探测策略找下一个空位置 缓存友好;无额外指针 删除需墓碑标记;负载因子不能高

五、自定义 Key 的要求

map 的 key 要求

需要定义 operator<(小于比较运算符),红黑树靠比较大小来排序和定位。

struct MyKey {
    int a, b;
    bool operator<(const MyKey& other) const {
        if (a != other.a) return a < other.a;
        return b < other.b;
    }
};
std::map<MyKey, int> m;  // ✅

力扣49. 字母异位词分组

方法一:排序
由于互为字母异位词的两个字符串包含的字母相同,因此对两个字符串分别进行排序之后得到的字符串一定是相同的,故可以将排序之后的字符串作为哈希表的键。

class Solution {

点击查看代码
class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        unordered_map<string, vector<string>> mp;
        for (string& str: strs) {
            string key = str;
            sort(key.begin(), key.end());
            mp[key].emplace_back(str);
        }
        vector<vector<string>> ans;
        for (auto it = mp.begin(); it != mp.end(); ++it) {
            ans.emplace_back(it->second);
        }
        return ans;
    }
};

复杂度分析

  • 时间复杂度:O(nklogk),其中 n 是 strs 中的字符串的数量,k 是 strs 中的字符串的的最大长度。需要遍历 n 个字符串,对于每个字符串,需要 O(klogk) 的时间进行排序以及 O(1) 的时间更新哈希表,因此总时间复杂度是 O(nklogk)。

  • 空间复杂度:O(nk),其中 n 是 strs 中的字符串的数量,k 是 strs 中的字符串的的最大长度。需要用哈希表存储全部字符串。

posted @ 2026-08-01 11:23  01y  阅读(5)  评论(0)    收藏  举报