代码随想录——哈希表
2026/5/11 7:01:30 网站建设 项目流程

当我们想使用哈希法来解决问题的时候,我们一般会选择如下三种数据结构。

  • 数组
  • set (集合)
  • map (映射)

这里数组就没啥可说的了,我们来看一下set。

在C++中,set 和 map 分别提供以下三种数据结构,其底层实现以及优劣如下表所示:

集合底层实现是否有序数值是否可以重复能否更改数值查询效率增删效率
std::set红黑树有序O(log n)O(log n)
std::multiset红黑树有序O(logn)O(logn)
std::unordered_set哈希表无序O(1)O(1)

std::unordered_set底层实现为哈希表,std::set 和std::multiset 的底层实现是红黑树,红黑树是一种平衡二叉搜索树,所以key值是有序的,但key不可以修改,改动key值会导致整棵树的错乱,所以只能删除和增加。

映射底层实现是否有序数值是否可以重复能否更改数值查询效率增删效率
std::map红黑树key有序key不可重复key不可修改O(logn)O(logn)
std::multimap红黑树key有序key可重复key不可修改O(log n)O(log n)
std::unordered_map哈希表key无序key不可重复key不可修改O(1)O(1)

std::unordered_map 底层实现为哈希表,std::map 和std::multimap 的底层实现是红黑树。同理,std::map 和std::multimap 的key也是有序的(这个问题也经常作为面试题,考察对语言容器底层的理解)。

当我们要使用集合来解决哈希问题的时候,优先使用unordered_set,因为它的查询和增删效率是最优的,如果需要集合是有序的,那么就用set,如果要求不仅有序还要有重复数据的话,那么就用multiset。

那么再来看一下map ,在map 是一个key value 的数据结构,map中,对key是有限制,对value没有限制的,因为key的存储方式使用红黑树实现的。

哈希表经典题目

数组作为哈希表

字母异位词等元素上界确定且不大是可以使用数组替换map,这样的空间消耗更小。

字母异位词

classSolution{public:boolisAnagram(string s,string t){intrecord[26]={0};for(inti=0;i<s.size();i++){// 并不需要记住字符a的ASCII,只要求出一个相对数值就可以了record[s[i]-'a']++;}for(inti=0;i<t.size();i++){record[t[i]-'a']--;}for(inti=0;i<26;i++){if(record[i]!=0){// record数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。returnfalse;}}// record数组所有元素都为零0,说明字符串s和t是字母异位词returntrue;}};

set(集合)作为哈希表

题目没有限制数值的大小,就无法使用数组来做哈希表了。

主要因为如下两点:

  • 数组的大小是有限的,受到系统栈空间(不是数据结构的栈)的限制。
  • 如果数组空间够大,但哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费。

所以此时一样的做映射的话,就可以使用set了。

两个数组交集

classSolution{public:vector<int>intersection(vector<int>&nums1,vector<int>&nums2){unordered_set<int>result_set;// 存放结果,之所以用set是为了给结果集去重unordered_set<int>nums_set(nums1.begin(),nums1.end());for(intnum:nums2){// 发现nums2的元素 在nums_set里又出现过if(nums_set.find(num)!=nums_set.end()){result_set.insert(num);}}returnvector<int>(result_set.begin(),result_set.end());}};

map作为哈希表

来说一说:使用数组和set来做哈希法的局限。

  • 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
  • set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,不仅要判断y是否存在而且还要记录y的下标位置,因为要返回x 和 y的下标。所以set 也不能用。

map是一种<key, value>的结构,本题可以用key保存数值,用value在保存数值所在的下标。所以使用map最为合适。

两数之和

classSolution{public:vector<int>twoSum(vector<int>&nums,inttarget){std::unordered_map<int,int>map;for(inti=0;i<nums.size();i++){// 遍历当前元素,并在map中寻找是否有匹配的keyautoiter=map.find(target-nums[i]);if(iter!=map.end()){return{iter->second,i};}// 如果没找到匹配对,就把访问过的元素和下标加入到map中map.insert(pair<int,int>(nums[i],i));}return{};}};

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询