当前位置:   article > 正文

哈希法c++_emplace_back哈希

emplace_back哈希

一、哈希表基础

哈希表(Hash Table)也称散列表,是根据关键码值(key, value)而直接进行访问的数据结构。

如何将键值映射到哈希表上? => 使用哈希函数

        1、将键值映射为哈希表上具体的索引数字:利用hashCode将键值转化为具体数值(hashcode通过特定编码方式,可以将其他数据格式转化为不同的数值)

        2、若hashCode得到的数值大于哈希表的大小:将得到的索引数字对哈希表的大小取模,保证键值一定可以映射到哈希表上。

        3、若有不同的键值映射到了同一个索引数值,则产生了哈希冲突

其中简化代码如下:

  1. //哈希函数:hash_function
  2. index_value=hash_function(key); //key是键值
  3. int hash_function(int key,int hash_size){
  4. return hash_code(key)%hash_size; //hash_size代表哈希表大小
  5. }

解决哈希冲突的方法

主要有两种方法:开放地址法和链地址法(也叫拉链法)

        1、开放地址法

        用开放定址法解决冲突的做法是:当冲突发生时,使用某种探测算法在散列表中寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到。按照探测序列的方法,一般将开放地址法区分为线性探查法、二次探查法、双重散列法等。(要求hash_size一定要大于data_size,要不然哈希表上就没有空置的位置来存放冲突的数据了)

        2、拉链法

        用拉链法解决冲突的做法是:当冲突发生时,将发生冲突的元素(键值)存储在链表中,可以通过索引找到发生冲突的元素。需要选择适当的哈希表的大小,这样既不会因为数组空值而浪费大量内存,也不会因为链表太长而在查找上浪费太多时间。

c++中哈希表的实现 

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

 上表来源于代码随想录

二、unordered_map基本操作

  1. int main()
  2. {
  3. //哈希表的初始化及插入
  4. unordered_map<int, string> hash_map={{ 1, "熊大" },{ 2, "熊二" }};//使用{}赋值
  5. hash_map[3] = "光头强"; //使用[ ]进行单个插入,若已存在键值3,则赋值修改,若无则插入。
  6. hash_map.insert(pair<int, string>(4, "拖拉机"));//使用insert和pair插入
  7. hash_map.emplace(pair<int, string>(5, "树"));//效率比 insert() 方法高
  8. //常见操作
  9. if(hash_map.find(2)!=hash_map.end()){
  10. cout<<"找到键值为2的值为"<<hash_map.at(2)<<endl;
  11. }
  12. hash_map.erase(2);//删除键值为2的成员
  13. cout << "hash_map size==" << hash_map.size() << endl;//输出hash_map大小
  14. //遍历输出
  15. for(auto it=hash_map.begin();it!=hash_map.end();it++){
  16. cout<<it->first<<" "<<it->second<<endl;
  17. }
  18. getchar();
  19. return 0;
  20. }

三、哈希表常见力扣题

3. 无重复字符的最长子串

  1. class Solution {
  2. public:
  3. int lengthOfLongestSubstring(string s) {
  4. unordered_set<char>res;
  5. int left=0,right=0;
  6. int length=0;
  7. while(right<s.size()){
  8. while(res.find(s[right])!=res.end()){//保证滑动窗口内没有重复字母
  9. res.erase(s[left]);
  10. left++;
  11. }
  12. res.insert(s[right]);
  13. length=max(length,right-left+1);
  14. right++;
  15. }
  16. return length;
  17. }
  18. };

17. 电话号码的字母组合

  1. class Solution {
  2. public:
  3. vector<string> letterCombinations(string digits) {
  4. vector<string> combinations;
  5. if(digits.empty()){
  6. return combinations;
  7. }
  8. unordered_map<char,string> phonemap={
  9. {'2',"abc"},
  10. {'3',"def"},
  11. {'4',"ghi"},
  12. {'5',"jkl"},
  13. {'6',"mno"},
  14. {'7',"pqrs"},
  15. {'8',"tuv"},
  16. {'9',"wxyz"}
  17. };
  18. string combination;
  19. backtrace(phonemap,combinations,digits,0,combination);
  20. return combinations;
  21. }
  22. void backtrace(const unordered_map<char,string>& phonemap,vector<string>& combinations,string& digits,int index,string& combination){
  23. if(index==digits.length())
  24. combinations.push_back(combination);
  25. else{
  26. char digit=digits[index];
  27. const string& letters=phonemap.at(digit);
  28. for(const char& letter:letters){
  29. combination.push_back(letter);
  30. backtrace(phonemap,combinations,digits,index+1,combination);
  31. combination.pop_back();
  32. }
  33. }
  34. }
  35. };

49. 字母异位词分组

  1. class Solution {
  2. public:
  3. vector<vector<string>> groupAnagrams(vector<string>& strs) {
  4. unordered_map<string,vector<string>> hashmap;
  5. for(string& str:strs){
  6. string key=str;
  7. sort(key.begin(),key.end());
  8. hashmap[key].emplace_back(str);
  9. }
  10. vector<vector<string>> res;
  11. for(auto it=hashmap.begin();it!=hashmap.end();it++){
  12. res.emplace_back(it->second);
  13. }
  14. return res;
  15. }
  16. };

76. 最小覆盖子串

  1. class Solution {
  2. public:
  3. unordered_map <char, int> ori, cnt;
  4. bool check(){
  5. for(const auto &it:ori){
  6. if(cnt[it.first]<it.second)
  7. return false;
  8. }
  9. return true;
  10. }
  11. string minWindow(string s, string t) {
  12. if(t.size()>s.size()) return {};
  13. int left=0,right=-1; //注意right初始化为-1
  14. int left_out=-1;
  15. int length=INT_MAX;
  16. string out={};
  17. for(const auto &it:t){
  18. ori[it]++;
  19. }
  20. while(right<int(s.size())){ //注意int类型转换,因为s.size()类型为unsigned int,right初始化为负数
  21. right++;
  22. if(ori.find(s[right])!=ori.end()){
  23. cnt[s[right]]++;
  24. }
  25. while(left<=right&&check()){
  26. if((right-left+1)<length){
  27. length=right-left+1; //记录最小串长度
  28. left_out=left; //记录最小串起始位置
  29. }
  30. if(ori.find(s[left])!=ori.end()){
  31. cnt[s[left]]--;
  32. }
  33. left++;
  34. }
  35. }
  36. //cout<<s[right];
  37. return left_out==-1?out:s.substr(left_out,length);
  38. }
  39. };

​​​​​​128. 最长连续序列

  1. class Solution {
  2. public:
  3. int longestConsecutive(vector<int>& nums) {
  4. unordered_set<int> hash;
  5. for(auto x:nums) hash.insert(x);
  6. int res=0;
  7. for(auto x:hash){
  8. if(!hash.count(x-1)){//找到最小的那个
  9. int y=x;
  10. while(hash.count(y+1))y++; //找最大的那个
  11. res=max(res,y-x+1);
  12. }
  13. }
  14. return res;
  15. }
  16. };

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/521182
推荐阅读
相关标签
  

闽ICP备14008679号