哈希表(Hash)
哈希表以键值对的方式存储,在查找元素方面时间复杂度为O(1),对于很多数组类题目相当有效。
哈希表分两种:
1.hashmap:<数据类型,数据类型>以键和值存储。
2.hashset<数据类型>以键存储,具有去重的效果。
以力扣里的题目作为练习,来吧。
1748唯一元素的和
给你一个整数数组 nums 。数组中唯一元素是那些只出现 恰好一次 的元素。
请你返回 nums 中唯一元素的 和 。
解:
点击查看代码
class Solution {
public:
int sumOfUnique(vector<int>& nums) {
unordered_map<int,int>mp;
int ans=0;
for(int i=0;i<nums.size();i++){
if(mp[nums[i]]==0){
ans+=nums[i];
mp[nums[i]]=1;
}else if(mp[nums[i]]==1){
ans-=nums[i];
mp[nums[i]]=2;
}
}
return ans;
}
};
点击查看代码
class Solution {
public:
bool divideArray(vector<int>& nums) {
unordered_map<int,int>mp;
if(nums.size()%2!=0)return false;
for(int i=0;i<nums.size();i++){
mp[nums[i]]++;
}
for(int i=0;i<nums.size();i++){
if(mp[nums[i]]%2!=0)return false;
}
return true;
}
};
1832. 判断句子是否为全字母句
全字母句 指包含英语字母表中每个字母至少一次的句子。
给你一个仅由小写英文字母组成的字符串 sentence ,请你判断 sentence 是否为 全字母句 。
如果是,返回 true ;否则,返回 false 。
解:
点击查看代码
class Solution {
public:
bool checkIfPangram(string sentence) {
if(sentence.size()<26)return false;
unordered_map<int,int> mp;
for(int i=0;i<sentence.size();i++){
mp[sentence[i]]++;
}
for(int i='a';i<='z';i++){
if(!mp[i])return false;
}
return true;
}
};
进阶练习
1512. 好数对的数目
给你一个整数数组 nums 。
如果一组数字 (i,j) 满足 nums[i] == nums[j] 且 i < j ,就可以认为这是一组 好数对 。
返回好数对的数目。
输入:nums = [1,2,3,1,1,3]
输出:4
解释:有 4 组好数对,分别是 (0,3), (0,4), (3,4), (2,5) ,下标从 0 开始
思路:组成数对的元素可以重复利用,在这里应当明白,在下列代码中,ans+=mp[nums[j]],nums[j]代表的是对应数组下标的元素值,而mp[nums[j]]则代表在0j-1中与nums[j]的值一样的个数,也就是好数对的数目(在1从0开始的循环中,我们把数组中的每个值都加入到了哈希表中,当我们nums[j]是一个已经在哈希表里>0的元素,我们就直接把他加入到我们的好数对的数量中,因为此时mp[nums[j]]代表的是在0j-1中nums[j]这个值出现的次数),然后我们当前的nums[j]对于后面的元素也是可以当作数对中的一个,要把它加到哈希表中
点击查看代码
class Solution {
public:
int numIdenticalPairs(vector<int>& nums) {
unordered_map<int,int>mp;
int ans=0;
for(int j=0;j<nums.size();j++){
ans+=mp[nums[j]];
mp[nums[j]]++;
}
return ans;
}
};
点击查看代码
class Solution {
public:
int countKDifference(vector<int>& nums, int k) {
unordered_map<int,int>mp;
int ans=0;
for(int i=0;i<nums.size();i++){
//解法1:
// ans+=(mp.count(nums[i]-k)?mp[nums[i]-k]:0);
// ans+=(mp.count(nums[i]+k)?mp[nums[i]+k]:0);
//解法2:
int x=nums[i]+k;
if(x>=1&&x<=100){
ans+= mp[x];
}
x=nums[i]-k;
if(x>=1&&x<=100){
ans+=mp[x];
}
mp[nums[i]]++;
}
return ans;
}
};
前缀和:在一个数组中,给出区间,想要快速知道区间内数组元素的和,我们可以采用前缀和的办法,即让每一个元素都加上在他前面的所有元素,这样求区间内的和就只需把区间左右两个下标的值相减即可
930. 和相同的二元子数组
给你一个二元数组 nums ,和一个整数 goal ,请你统计并返回有多少个和为 goal 的 非空 子数组。
子数组 是数组的一段连续部分。
输入:nums = [1,0,1,0,1], goal = 2
输出:4
解释:有 4 个满足题目要求的子数组:[1,0,1]、[1,0,1,0]、[0,1,0,1]、[1,0,1]
思路:这一题涉及到非空子数组,同时还涉及到和,子数组是连续的,因此我们可以采用前缀和的方式快速计算,
题解:
点击查看代码
class Solution {
public:
int numSubarraysWithSum(vector<int>& nums, int goal) {
unordered_map<int, int> mp;
mp[0] = 1; // 初始前缀和为0出现1次(虚拟索引-1)
int sum = 0, ans = 0;
for (int num : nums) {
sum += num; // 当前前缀和
ans += mp[sum - goal]; // 累加符合条件的子数组数量
mp[sum]++; // 更新哈希表
}
return ans;
}
};
浙公网安备 33010602011771号