哈希表
哈希表
题解
这是开链表(链表形结构)。
typedef struct LinkedList { struct LinkedList *next; int key; // value,key-value 对。 } ListNode; typedef struct { ListNode *head; } MyHashSet; const int size=9973; ListNode *init() { ListNode *Node=(ListNode *) malloc(sizeof(ListNode)); Node->key=0; Node->next=NULL; return Node; } void delete(ListNode *head) { if(head==NULL) return; ListNode *delNode=head,*delNext=delNode->next; while(delNext!=NULL) { free(delNode); delNode=delNext; if(delNext!=NULL) delNext=delNext->next; } } // 创建散列表。 MyHashSet *myHashSetCreate() { MyHashSet *obj=(MyHashSet *) malloc(sizeof(MyHashSet)*size); for(int i=0;i<size;i++) obj[i].head=NULL; return obj; } // 添加元素。 void myHashSetAdd(MyHashSet *obj, int key) { int realDst=key % size; ListNode *storeDst; // 头节点为空,现行处理头节点。 if(obj[realDst].head==NULL) { obj[realDst].head=init(); storeDst=obj[realDst].head; storeDst->key=key; return; } //头节点非空,移到链表末尾。 storeDst=obj[realDst].head; if(storeDst->key==key) return; while(storeDst->next != NULL) { storeDst=storeDst->next; if(storeDst->key==key) return; } storeDst->next=init(); storeDst=storeDst->next; storeDst->key=key; } void myHashSetRemove(MyHashSet *obj, int key) { int realDst=key % size; if(obj[realDst].head==NULL) return; ListNode *removeDst=obj[realDst].head; // 1. 处理是头节点的情况。 if(removeDst->key == key) { obj[realDst].head=removeDst->next; free(removeDst); removeDst=NULL; return; } // 2. 处理中间节点。 ListNode *removePre=removeDst; while(removeDst!=NULL) { if(removeDst->key==key) break; else { removePre=removeDst; removeDst=removeDst->next; } } if(removeDst==NULL) return; // 没有可以删除的,直接返回。 removePre->next=removeDst->next; free(removeDst); removeDst=NULL; removePre=NULL; } // 判断key是否存在。 bool myHashSetContains(MyHashSet *obj, int key) { int checkDst=key % size; if(obj[checkDst].head==NULL) return false; ListNode *check=obj[checkDst].head; while(check!=NULL) { if(check->key==key) return true; check=check->next; } return false; } void myHashSetFree(MyHashSet *obj) { for(int i=0;i<size;i++) { if(obj[i].head==NULL) continue; delete(obj[i].head); } } /** * Your MyHashSet struct will be instantiated and called as such: * MyHashSet* obj = myHashSetCreate(); * myHashSetAdd(obj, key); * myHashSetRemove(obj, key); * bool param_3 = myHashSetContains(obj, key); * myHashSetFree(obj); */
题解
typedef struct LinkedList { struct LinkedList *next; int key; int value; } ListNode; typedef struct { ListNode *head; } MyHashMap; const int size=9973; ListNode *init() { ListNode *Node=(ListNode *) malloc(sizeof(ListNode)); Node->key=0; Node->next=NULL; return Node; } void delete(ListNode *head) { if(head==NULL) return; ListNode *delNode=head,*delNext=delNode->next; while(delNext!=NULL) { free(delNode); delNode=delNext; if(delNext!=NULL) delNext=delNext->next; } } // 创建散列表。 MyHashMap *myHashMapCreate() { MyHashMap *obj=(MyHashMap *) malloc(sizeof(MyHashMap)*size); for(int i=0;i<size;i++) obj[i].head=NULL; return obj; } // 添加元素。 void myHashMapPut(MyHashMap *obj, int key, int value) { int realDst=key % size; ListNode *storeDst; // 头节点为空,现行处理头节点。 if(obj[realDst].head==NULL) { obj[realDst].head=init(); storeDst=obj[realDst].head; storeDst->key=key; storeDst->value=value; return; } //头节点非空,移到链表末尾。 storeDst=obj[realDst].head; if(storeDst->key==key) { storeDst->value=value; return; } while(storeDst->next != NULL) { storeDst=storeDst->next; if(storeDst->key==key) { storeDst->value=value; return; } } storeDst->next=init(); storeDst=storeDst->next; storeDst->key=key; storeDst->value=value; } void myHashMapRemove(MyHashMap *obj, int key) { int realDst=key % size; if(obj[realDst].head==NULL) return; ListNode *removeDst=obj[realDst].head; // 1. 处理是头节点的情况。 if(removeDst->key == key) { obj[realDst].head=removeDst->next; free(removeDst); removeDst=NULL; return; } // 2. 处理中间节点。 ListNode *removePre=removeDst; while(removeDst!=NULL) { if(removeDst->key==key) break; else { removePre=removeDst; removeDst=removeDst->next; } } if(removeDst==NULL) return; // 没有可以删除的,直接返回。 removePre->next=removeDst->next; free(removeDst); removeDst=NULL; removePre=NULL; } // 判断key是否存在。 int myHashMapGet(MyHashMap *obj, int key) { int checkDst=key % size; if(obj[checkDst].head==NULL) return -1; ListNode *check=obj[checkDst].head; while(check!=NULL) { if(check->key==key) return check->value; check=check->next; } return -1; } void myHashMapFree(MyHashMap *obj) { for(int i=0;i<size;i++) { if(obj[i].head==NULL) continue; delete(obj[i].head); } }
题解
用自己的模版:
const int size=99991; // 哈希表的动态分配大小,最好是质数。 typedef struct LinkedList { struct LinkedList *next; int key; // value,key-value 对。 } ListNode; // 定义散列表。散列表存储的是相同映射的头节点。 typedef struct HashSet { ListNode *head; }MyHashSet; ListNode *init() { ListNode *Node=(ListNode *) malloc(sizeof(ListNode)); Node->key=0; Node->next=NULL; return Node; } void delete(ListNode *head) { if(head==NULL) return; ListNode *delNode=head,*delNext=delNode->next; while(delNext!=NULL) { free(delNode); delNode=delNext; if(delNext) delNext=delNext->next; } } // 创建散列表。 MyHashSet *myHashSetCreate() { MyHashSet *obj=(MyHashSet *) malloc(sizeof(MyHashSet)*size); for(int i=0;i<size;i++) obj[i].head=NULL; return obj; } // 添加元素。 void myHashSetAdd(MyHashSet *obj, int key) { int realDst=abs(key % size); ListNode *storeDst; // 头节点为空,现行处理头节点。 if(obj[realDst].head==NULL) { obj[realDst].head=init(); storeDst=obj[realDst].head; storeDst->key=key; return; } //头节点非空,移到链表末尾。 storeDst=obj[realDst].head; if(storeDst->key==key) return; while(storeDst->next != NULL) { if(storeDst->key==key) return; storeDst=storeDst->next; } storeDst->next=init(); storeDst=storeDst->next; storeDst->key=key; } void myHashSetRemove(MyHashSet *obj, int key) { int realDst=abs(key % size); if(obj[realDst].head==NULL) return; ListNode *removeDst=obj[realDst].head; // 1. 处理是头节点的情况。 if(removeDst->key == key) { obj[realDst].head=removeDst->next; free(removeDst); removeDst=NULL; return; } // 2. 处理中间节点。 ListNode *removePre=removeDst; while(removeDst!=NULL) { if(removeDst->key==key) break; else { removePre=removeDst; removeDst=removeDst->next; } } if(removeDst==NULL) return; // 没有可以删除的,直接返回。 removePre->next=removeDst->next; free(removeDst); removeDst=NULL; removePre=NULL; } // 判断key是否存在。 bool myHashSetContains(MyHashSet *obj, int key) { int checkDst=abs(key % size); if(obj[checkDst].head==NULL) return false; ListNode *check=obj[checkDst].head; while(check!=NULL) { if(check->key==key) return true; check=check->next; } return false; } void myHashSetFree(MyHashSet *obj) { for(int i=0;i<size;i++) { if(obj[i].head==NULL) continue; delete(obj[i].head); } } bool containsDuplicate(int* nums, int numsSize) { MyHashSet *obj=myHashSetCreate(); bool flag=false; for(int i=0;i<numsSize;i++) { flag=myHashSetContains(obj,nums[i]); if(flag==true) return flag; myHashSetAdd(obj,nums[i]); } return flag; }
尝试学习C++的STL。
class Solution { public: bool containsDuplicate(vector<int>& nums) { unordered_set<int> s; ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); for(auto x:nums) { if(s.find(x)!=s.end()) return true; s.insert(x); } return false; } };
题解
class Solution { public: vector<int> intersection(vector<int>& nums1, vector<int>& nums2) { unordered_set<int> set1,set2; for(auto x:nums1) set1.insert(x); for(auto x:nums2) set2.insert(x); vector<int> ans; if(set1.size()>set2.size()) { for(auto &x:set2) { if(set1.contains(x)) ans.push_back(x); } } else { for(auto &x:set1) { if(set2.contains(x)) ans.push_back(x); } } return ans; } };
题解二
使用merge函数。
a.merge(b)
class Solution { public: vector<int> intersection(vector<int>& nums1, vector<int>& nums2) { unordered_set<int> set1,set2; for(auto x:nums1) set1.insert(x); for(auto x:nums2) set2.insert(x); vector<int> ans; set1.merge(set2); for(auto &x:set2) ans.push_back(x); return ans; } };
注释
unordered_set<template>
是哈希无序集合。一般用:
1. find(T)
来返回元素所处于的迭代器地址。
2. count(T)
来返回含有的指定元素的个数。
3. contains(T)
返回集合中是否具有该元素。
采用有序的set。
class Solution { public: int longestConsecutive(vector<int>& nums) { set<int> s; ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); for(auto i:nums) { s.insert(i); } int count=0; int ans=0; int pre,current; for (auto &x:s) { if(count==0) { pre=x; count++; continue; } current=x; if(current==pre+1) { count++; pre=current; continue; } else { ans=count>ans?count:ans; pre=current; count=1; } } ans=count>ans?count:ans; return ans; } };
思路
注意采用两个无序映射。需要分别检查pattern与substring的关系,也要检查substring与pattern的关系,检查他们的双射关系。
分隔字符串采用substr(pos,num)
函数。寻找下标。分隔为
最后要注意匹配时要将pattern全部使用完成。
题解
class Solution { public: bool wordPattern(string pattern, string s) { unordered_map<char,string> p; unordered_map<string,char> q; int i=0,cnt=0,j=0; string substring; while(i<s.size()) { while(s[i+cnt]!=' ') { cnt++; if(i+cnt>=s.size()) break; } substring=s.substr(i,cnt); i=i+cnt+1; cnt=0; if(p.find(pattern[j])==p.end()) p.emplace(make_pair(pattern[j],substring)); if(p[pattern[j]]!=substring) return false; if(q.find(substring)==q.end()) q.emplace(make_pair(substring,pattern[j])); if(q[substring]!=pattern[j]) return false; j++; } if(j!=pattern.size()) return false; return true; } };
思路
采用有序的哈希表进行计数。并且寻找当前数+k是否存在即可。
注意区分讨论k=0.
题解
class Solution { public: int findPairs(vector<int>& nums, int k) { map<int,int> p; for(auto i:nums) { if(p.find(i)==p.end()) p.emplace(make_pair(i,1)); else p[i]++; } int ans=0; if(k==0) { for(auto &[i,cnt]:p) { if(cnt>1) ans++; } return ans; } else { for(auto &[i,cnt]:p) { if(p.contains(i+k)) ans++; } return ans; } } };
思路1
创建两个哈希表,一个将原有node映射到下标,一个将下标映射到现有的node.
/* // Definition for a Node. class Node { public: int val; Node* next; Node* random; Node(int _val) { val = _val; next = NULL; random = NULL; } }; */ class Solution { public: Node* copyRandomList(Node* head) { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); if(!head) return nullptr; // build 2 hash map. // hashmap 1: original node -> index; // hashmap 2: index -> new node; Node *original_chain=head; unordered_map<Node*,int> Node2index; unordered_map<int,Node*> index2Node; int index=0; while(original_chain) { Node2index.emplace(make_pair(original_chain,index++)); original_chain=original_chain->next; } Node2index.emplace(make_pair(nullptr,index)); original_chain=head; index=0; Node *new_chain=new Node(original_chain->val); Node *read_new=new_chain; index2Node.emplace(make_pair(index++,read_new)); while(original_chain->next) { read_new->next=new Node(original_chain->next->val); index2Node.emplace(make_pair(index++,read_new->next)); original_chain=original_chain->next; read_new=read_new->next; } index2Node.emplace(make_pair(index++,nullptr)); original_chain=head; read_new=new_chain; while(original_chain) { int ind=Node2index[original_chain->random]; Node *rand=index2Node[ind]; read_new->random=rand; read_new=read_new->next; original_chain=original_chain->next; } return new_chain; } };
思路2(更好)
采用递归+回溯的方法,可以更好地只采用一个哈希映射进行。
class Solution { public: unordered_map<Node*, Node*> cachedNode; Node* copyRandomList(Node* head) { if (head == nullptr) { return nullptr; } if (!cachedNode.count(head)) { Node* headNew = new Node(head->val); cachedNode[head] = headNew; headNew->next = copyRandomList(head->next); headNew->random = copyRandomList(head->random); } return cachedNode[head]; } };
思路
遍历整个数组。并且将数组中的数字累加得到新的边界标记。利用哈希表存储边界标记并得到最大标记即可。
class Solution { public: int leastBricks(vector<vector<int>>& wall) { int range=0; for(int i=0;i<wall[0].size();i++) range+=wall[0][i]; map<int,int> bucket; int maximum=0; for(auto &row:wall) { int mark=0; for(auto i:row) { mark+=i; if(mark<range && mark>0) { bucket[mark]++; maximum=max(bucket[mark],maximum); } } } return wall.size()-maximum; } };
class Solution { public: void cut(string &str,multimap<string,string> &m) { string path=""; int i; for(i=0;i<str.size();i++) { if(str[i]==' ') break; path+=str[i]; } path+='/'; i++; string doc=""; string contents=""; for(;i<str.size();i++) { if(str[i]=='(') { i++; while(str[i]!=')') contents+=str[i++]; } if(str[i]==')') { m.emplace(make_pair(contents,path+doc)); continue; } if(str[i]==' ') { doc=""; contents=""; continue; } doc+=str[i]; } } vector<vector<string>> findDuplicate(vector<string>& paths) { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); multimap<string,string> pathWithContents; for(auto &i:paths) { cut(i,pathWithContents); } vector<vector<string> > ans; vector<string> ans_temp; string content=""; for(auto &[con,doc]:pathWithContents) { if(content=="") { content=con; ans_temp.push_back(doc); } else if(content==con) { ans_temp.push_back(doc); } else { if(ans_temp.size()>1) { ans.push_back(ans_temp); ans_temp={}; ans_temp.push_back(doc); content=con; } else { ans_temp={}; ans_temp.push_back(doc); content=con; } } } if(ans_temp.size()>1) ans.push_back(ans_temp); return ans; } };
思路
分组哈希。
题解
class Solution { public: int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) { unordered_map<int,int> p; ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); for (auto i:nums1) { for(auto j:nums2) p[i+j]++; } int ans=0; for(auto k:nums3) { for(auto l:nums4) ans+=p[-k-l]; } return ans; } };
前缀和+哈希表
我们遍历数组,利用哈希表记录下前缀和的值和相同前缀和值出现的次数。
我们的目的是为了
这样我们就有
题解
class Solution { public: int subarraySum(vector<int>& nums, int k) { unordered_map<int,int> p; ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); p[0]++; int temp=0; int ans=0; for(auto i:nums) { temp+=i; if(p.find(temp-k)!=p.end()) ans+=p[temp-k]; p[temp]++; } return ans; } };
前缀和+哈希。这里要注意采用的存取方式是前缀和mod k
的余数。
为什么?
有:
因此当出现间隔超过1的余数相同的前缀时,就存在一个区间使得其中的和是k的倍数。
class Solution { public: bool checkSubarraySum(vector<int>& nums, int k) { // prefix sum + hash table. unordered_map<int,int> p; int temp=0; int index=0; ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); p.emplace(make_pair(0,-1)); for(index=0;index<nums.size();index++) { temp=(temp+nums[index])%k; if(p.find(temp)!=p.end() && index-p[temp]>1) return true; else p.emplace(make_pair(temp,index)); } return false; } };
题解
注意unordered_map(map)和unordered_set(set)的单一性。一个key只能对应一个value。我们将
只需要保留首次出现sum时的数组索引下标即可。剩下的全部只进行长度的计算。
0 0 1 0 0 0 1 1 1 1 //nums 0 -1 -2 -1 -2 -3 -4 -3 -2 -1 0 //prefix 0 0 2 2 2 2 2 4 6 8 //length
class Solution { public: int findMaxLength(vector<int>& nums) { // prefix sum and hash. // prefix sum and hash. unordered_map<int,int> p; p[0]=-1; int index=0; int sum=0; int ans=0; for(auto i:nums) { // find 1 and -1. sum+=(i==0)?-1:1; if(p.find(sum)!=p.end()) { ans=ans>index-p[sum]?ans:index-p[sum]; index++; } else p.emplace(make_pair(sum,index++)); } return ans; } };
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了