哈希表
设计哈希表
设计哈希集合
#define MAX_LEN 100000 // 初始化桶的数量
class MyHashSet {
private:
vector<int> set[MAX_LEN]; // 使用数组实现哈希集合
/** 返回对应的桶的索引 */
int getIndex(int key) {
return key % MAX_LEN;
}
/** 在特定的桶中搜索键,如果该键不存在则返回 -1 */
int getPos(int key, int index) {
// 每个桶中包含一个列表,遍历所有桶中的元素来寻找特定的键
for (int i = 0; i < set[index].size(); ++i) {
if (set[index][i] == key) {
return i;
}
}
return -1;
}
public:
MyHashSet() {
}
void add(int key) {
int index = getIndex(key);
int pos = getPos(key, index);
if (pos < 0) {
// 如果键不存在,则添加
set[index].push_back(key);
}
}
void remove(int key) {
int index = getIndex(key);
int pos = getPos(key, index);
if (pos >= 0) {
// 如果键存在,则删除
set[index].erase(set[index].begin() + pos);
}
}
bool contains(int key) {
int index = getIndex(key);
int pos = getPos(key, index);
return pos >= 0;
}
};
作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/hash-table-plus/x79eft/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
设计哈希映射
#define MAX_LEN 100000 // 初始化桶的数量
class MyHashMap {
private:
vector<pair<int, int>> map[MAX_LEN]; // 使用数组实现哈希集合
/** 返回指定桶的索引 */
int getIndex(int key) {
return key % MAX_LEN;
}
/** 在桶中搜索键,如果不存在则返回 -1 */
int getPos(int key, int index) {
// 每个桶包含一个数组,遍历桶中的所有元素来查找指定的 key
for (int i = 0; i < map[index].size(); ++i) {
if (map[index][i].first == key) {
return i;
}
}
return -1;
}
public:
MyHashMap() {
}
/** value 始终为正 */
void put(int key, int value) {
int index = getIndex(key);
int pos = getPos(key, index);
if (pos < 0) {
map[index].push_back(make_pair(key, value));
} else {
map[index][pos].second = value;
}
}
/** 如果存在映射关系,则返回 value,否则返回 -1 */
int get(int key) {
int index = getIndex(key);
int pos = getPos(key, index);
if (pos < 0) {
return -1;
} else {
return map[index][pos].second;
}
}
/** 如果存在 key 的映射,则删除该映射关系 */
void remove(int key) {
int index = getIndex(key);
int pos = getPos(key, index);
if (pos >= 0) {
map[index].erase(map[index].begin() + pos);
}
}
};
作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/hash-table-plus/x79eft/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
哈希集合
哈希集合的操作
#include <unordered_set>
int main() {
// 1. 初始化哈希集
unordered_set<int> hashset;
// 2. 新增键
hashset.insert(3);
hashset.insert(2);
hashset.insert(1);
// 3. 删除键
hashset.erase(2);
// 4. 查询键是否包含在哈希集合中
if (hashset.count(2) <= 0) {
cout << "键 2 不在哈希集合中" << endl;
}
// 5. 哈希集合的大小
cout << "哈希集合的大小为: " << hashset.size() << endl;
// 6. 遍历哈希集合
for (auto it = hashset.begin(); it != hashset.end(); ++it) {
cout << (*it) << " ";
}
cout << "在哈希集合中" << endl;
// 7. 清空哈希集合
hashset.clear();
// 8. 查看哈希集合是否为空
if (hashset.empty()) {
cout << "哈希集合为空!" << endl;
}
}
作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/hash-table-plus/x79eft/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
哈希集合查重
/*
* 使用哈希集合寻找重复元素的模板
*/
bool findDuplicates(vector<Type>& keys) {
// 将 type 替换为 keys 的实际类型
unordered_set<Type> hashset;
for (Type key : keys) {
if (hashset.count(key) > 0) {
return true;
}
hashset.insert(key);
}
return false;
}
作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/hash-table-plus/x79eft/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
哈希映射
哈希表的操作
#include <unordered_map>
int main() {
// 1. 初始化哈希表
unordered_map<int, int> hashmap;
// 2. 插入一个新的(键,值)对
hashmap.insert(make_pair(0, 0));
hashmap.insert(make_pair(2, 3));
// 3. 插入一个新的(键,值)对,或者更新值
hashmap[1] = 1;
hashmap[1] = 2;
// 4. 获得特定键对应的值
cout << "The value of key 1 is: " << hashmap[1] << endl;
// 5. 删除键
hashmap.erase(2);
// 6. 检查键是否存在于哈希表中
if (hashmap.count(2) <= 0) {
cout << "键 2 不在哈希表中" << endl;
}
// 7. 哈希表的大小
cout << "哈希表的大小为: " << hashmap.size() << endl;
// 8. 遍历哈希表
for (auto it = hashmap.begin(); it != hashmap.end(); ++it) {
cout << "(" << it->first << "," << it->second << ") ";
}
cout << "在哈希表中" << endl;
// 9. 清空哈希表
hashmap.clear();
// 10. 检查哈希表是否为空
if (hashmap.empty()) {
cout << "哈希表为空!" << endl;
}
}
作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/hash-table-plus/x79eft/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/hash-table-plus/x7ejcs/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
map<int,int> mp;
for(int i=0;i<nums.size();i++)
{
if(mp.count(target-nums[i])==0)
mp[nums[i]]=i;
else
return{i,mp[target-nums[i]]};
}
return {};
}
};
同构字符串
给定两个字符串 s 和 t,判断它们是否是同构的。
如果 s 中的字符可以按某种映射关系替换得到 t ,那么这两个字符串是同构的。
每个出现的字符都应当映射到另一个字符,同时不改变字符的顺序。不同字符不能映射到同一个字符上,相同字符只能映射到同一个字符上,字符可以映射到自己本身。
作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/hash-table-plus/x7oyyd/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
bool isIsomorphic(string s, string t) {
map<char,char> mp;
//用于查看哈希表中已存在哪些字符
map<char,int>value;
for(int i=0;i<s.size();i++)
{
//遍历s和t中的字符,当s中的字符不在哈希表里时把s作为键,t作为值加入到哈希表里
//存储值的哈希表放入t中的值,如果大于1说明已经存放过,返回false
if(mp.count(s[i])==0)
{
if(value[t[i]]!=0)
return false;
value[t[i]]++;
mp[s[i]]=t[i];
}
//否则,查询当前字符的映射是否和哈希表中的映射对应
else{
//不同的字符映射到同一个字符上返回false
//当s的字符哈希映射后与当前字符不匹配返回false
if(mp[s[i]]!=t[i])
return false;
}
}
return true;
}
};
两个列表的最小索引总和
假设Andy和Doris想在晚餐时选择一家餐厅,并且他们都有一个表示最喜爱餐厅的列表,每个餐厅的名字用字符串表示。
你需要帮助他们用最少的索引和找出他们共同喜爱的餐厅。 如果答案不止一个,则输出所有答案并且不考虑顺序。 你可以假设总是存在一个答案。
作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/hash-table-plus/x7rs1h/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
vector<string> findRestaurant(vector<string>& list1, vector<string>& list2) {
map<string,int> canteen;
int len1=list1.size();
int len2=list2.size();
if(len1==0||len2==0)
return {};
for(int i=0;i<list1.size();i++)
{
//哈希表先存list1中的餐厅,映射关系为对应的下标,为区分零下标和初始值0,用下标+1
canteen.insert(pair<string,int>(list1[i],i));
}
int indexMin=10000;
//记录当前索引和对应的字符串
map<int, vector<string>> indexSum;
for(int i=0;i<list2.size();i++)
{
//然后遍历list2看有没有已经存在哈希表中的餐厅
//如果有,看是不是最小索引和
if(canteen.find(list2[i])!=canteen.end())
{
//索引和是两个列表的下标相加
int index=canteen[list2[i]]+i;
if(index<=indexMin)
{
indexMin=index;
indexSum[indexMin].push_back(list2[i]);
}
//res.push_back(list2[i]);
}
}
return indexSum[indexMin];
}
};
存在重复元素Ⅱ
给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的 绝对值 至多为 k。
作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/hash-table-plus/x7m3zm/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
bool containsNearbyDuplicate(vector<int>& nums, int k) {
map<int,int> mp;
for(int i=0;i<nums.size();i++)
{
//每次找到这个数字就先判断坐标是是不是满足条件
if(mp.find(nums[i])!=mp.end())
if(i-mp[nums[i]]<=k)
return true;
//不满足就继续找
mp[nums[i]]=i;
}
return false;
}
};
替换后的最长重复字符
给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字符,总共可最多替换 k 次。在执行上述操作后,找到包含重复字母的最长子串的长度。
注意:字符串长度 和 k 不会超过 104。
作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/hash-table-plus/x7auk1/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
int characterReplacement(string s, int k) {
//分别保存窗口的左边和右边的下标
int res=0,left=0,right=0;
map<char,int> mp;
//保存当前窗口的相同字符最大长度
int curMaxlen=INT_MIN;
while(right<s.size())
{
mp[s[right]]++;
curMaxlen=max(curMaxlen,mp[s[right]]);
//如果当前窗口的最大字符长度+可换字符的长度>=窗口长度说明满足题意
if((curMaxlen+k)>=(right-left+1))
right++;
else{
//如果不满足,整个窗口移动直到满足题意
mp[s[left]]--;
left++;
right++;
}
}
//最终的长度就是窗口的长度-1
return right-left;
}
};
最大连续1的个数Ⅲ
给定一个由若干 0
和 1
组成的数组 A
,我们最多可以将 K
个值从 0 变成 1 。
返回仅包含 1 的最长(连续)子数组的长度。
class Solution {
public:
int longestOnes(vector<int>& nums, int k) {
map<int,int> map;
int left=0,right=0,res=0,oneSum=0;
while(right!=nums.size())
{
//往右走,是1,当前窗口1的数量就+1
if(nums[right]==1)
oneSum++;
//满足当前1的长度+可修改长度>=窗口的长度时,快指针继续走
if(oneSum+k>=right-left+1)
right++;
else{
//否则就移动窗口,并把看最左边那个元素是不是1,是1就把当前1的数量-1
if(nums[left]==1)
oneSum--;
//移动整个窗口
left++;
right++;
}
}
//最终滑动窗口的长度-1就是1的最长数组
return right-left;
}
};
至多包含两个不同字符的最长子串
给定一个字符串 *s* ,找出 至多 包含两个不同字符的最长子串 *t* ,并返回该子串的长度。
class Solution {
public:
int lengthOfLongestSubstringTwoDistinct(string s) {
//快慢指针指向的坐标值,不同字母的个数初始值为0
int left=0,right=0,diff=0;
map<char,int> repeatCount;
while(right<s.size())
{
//没出现过,新字符+1
if(repeatCount[s[right]]==0)
diff++;
repeatCount[s[right]]++;
//新字符大于2,窗口左移
if(diff>2)
{
repeatCount[s[left]]--;
//最左边的字符只出现一次,左移之后新字符-1
if(repeatCount[s[left]]==0)
diff--;
left++;
}
right++;
}
return right-left;
}
};