哈希常见面试题——C++版
Posted ych9527
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了哈希常见面试题——C++版相关的知识,希望对你有一定的参考价值。
两个数组的交集
给定两个数组,编写一个函数来计算它们的交集。输出结果是唯一确定的
题解:
用两个set分别存储两个数组中的元素,达到去重的效果,然后用其中一个数组去另外一个数组中进行查找
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
//将nums1装入set1(去重)
//将num2装入set2,然后用set2的元素取set1中去寻找
unordered_set<int> st1;
unordered_set<int> st2;
for(auto&e:nums1)
{
st1.insert(e);
}
for(auto&e:nums2)
{
st2.insert(e);
}
vector<int> ret;
for(auto&e:st2)
{
if(st1.find(e)!=st1.end())
ret.push_back(e);
}
return ret;
}
};
时间复杂度:查找效率为O(1),存储元素为O(M+N) -> O(M+N)
空间复杂度O(M+N)
两个数组的交集II
给定两个数组,编写一个函数来计算它们的交集。
输出结果中每个元素出现的次数,应与元素在两个数组中出现次数的最小值一致。
题解:
用两个map分别记录数组中出现的元素的次数,然后用一个map中的去另外一个map中进行寻找,找到了后,再根据second判断需要返回多少个值
class Solution {
public:
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
unordered_map<int,int> mp1;
unordered_map<int,int> mp2;
for(auto&e:nums1)
{
mp1[e]++;
}
for(auto&e:nums2)
{
mp2[e]++;
}
vector<int> ret;
for(auto&e:mp2)
{
auto it=mp1.find(e.first);
if(it!=mp1.end())
{
int num=fmin(it->second,e.second);//得到有多少个相同的
for(int i=0;i<num;i++)
{
ret.push_back(e.first);
}
}
}
return ret;
}
};
存在重复元素
用map进行统计次数,如果有出现两次的直接返回
class Solution {
public:
bool containsDuplicate(vector<int>& nums) {
unordered_map<int,int> mp;
for(auto&e:nums)
{
mp[e]++;
if(mp[e]==2)
return true;
}
return false;
}
};
两句话中的不常见单词
给定两个句子 A 和 B 。 (句子是一串由空格分隔的单词。每个单词仅由小写字母组成。)如果一个单词在其中一个句子中只出现一次,在另一个句子中却没有出现,那么这个单词就是不常见的。返回所有不常用单词的列表。您可以按任何顺序返回列表。
题解:
题意转换 -> 两个句子中,只出现一次的单词
用哈希表进行统计 -> 并且将只出现一次的返回即可
技巧:将两个字符串和成一个字符串,并且,将这个字符串的所有单词放入哈希表之中,然后寻找哈希表中只出现一次的单词,再将这个单词返回即可。寻找单词的过程可以转变为寻找空格,即给定两个位置,pos1为单词的起始位置,pos2位空格的位置,pos1和pos2之间就是需要寻找的单词
class Solution {
public:
vector<string> uncommonFromSentences(string s1, string s2) {
//题意转换 -> 两个句子中,只出现一次的单词
//用哈希表进行统计 -> 并且将只出现一次的返回即可
vector<string> ret;
unordered_map<string,int> mp;
if(!s1.empty())//不为空则先加个空格
s1+=' ';
s1+=s2;
if(s1.empty())
return ret;
//此时s1最少有一个单词
size_t pos1=0;
size_t pos2=s1.find(' ');
while(pos2!=string::npos)
{
string temp(s1.begin()+pos1,s1.begin()+pos2);
mp[temp]++;//添加至mp之中
pos1=pos2+1;//来到下一个单词的起始处
pos2=s1.find(' ',pos1);//从pos1处开始寻找下一个空格
}
//此时,还剩下一个单词没有添加
mp[string(s1.begin()+pos1,s1.end())]++;
for(auto&e:mp)
{
if(e.second==1)//只出现一次的
ret.push_back(e.first);
}
return ret;
}
};
字母异位词分组
给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。
题解:
利用unordered_multimap,将每个字符串排序后的结果作为k值,没有排序的字符串作为v值
然后对map进行遍历,将具有相同k值的map的v值,添加至同一个数组之中
class Solution {
public:
void Insert(unordered_multimap<string,string>& map,string &s)
{
string copy(s);//预留一份
sort(s.begin(),s.end());//排序
map.insert(make_pair(s,copy));//插入map之中
}
vector<vector<string>> groupAnagrams(vector<string>& strs) {
unordered_multimap<string,string> map;
for(auto &s:strs)
{
Insert(map,s);
}
vector<vector<string>> ret;
string prev;
vector<string> temp;
for(auto &e:map)
{
if(e.first==prev)//和前面的相等
{
temp.push_back(e.second);
}
else
{
if(!temp.empty())
ret.push_back(temp);
prev=e.first;
temp.clear();
temp.push_back(e.second);
}
}
if(!temp.empty())
{
ret.push_back(temp);
}
return ret;
}
};
单词拆分
给定一个非空字符串 s 和一个包含非空单词的列表 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。
说明:
拆分时可以重复使用字典中的单词。
你可以假设字典中没有重复的单词。
题解:
先将单词添加至哈希表中,设dp[i]表示字符串s中0-i的单词是否可以从哈希表中挑选出单词组成
此时需要构建双重循环,外层循环更新i的位置,里层循环for(int j=i;j>=0;j–)表示 j-i的组成的单词是否可以从哈希表中找到对应的单词
如果s[j,i]能够找到对应的单词 ,dp[i]=dp[j-1] (j是当前匹配单词的第一个字母,0—i匹配的前提是 0—j-1的字符串也是匹配的)
**注意点:**当dp[i]==true时,就进行剪枝,不再对当前点进行判断,否则容易造成重复判断,出现不匹配的情况
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
//将单词添加至哈希表中
unordered_set<string> set;
for(auto& s:wordDict)
{
set.insert(s);
}
vector<bool>dp(s.size()+1,false);//dp[i]表示0-i的字符是否可以由字典里的单词构成
dp[0]=true;
for(int i=0;i<s.size();i++)
{
for(int j=i;j>=0;j--)
{
if(dp[i+1])
break;//剪枝,避免重复判断
string temp(s.begin()+j,s.begin()+i+1);
if(set.find(temp)!=set.end())//可以找到
{
dp[i+1]=dp[j];
}
}
}
return dp[s.size()];
}
};
和为K的子数组
给定一个整数数组和一个整数 **k,**你需要找到该数组中和为 k 的连续的子数组的个数。
题解:
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
//设 1 -i 下标的连续数组和为 sum[i]
//sum[i] - sum[j] =k -> sum[j] = sum[i] - k
//即在其中寻找,是否两个连续数组相减 == k
//此时需要注意的有如下几点
//1.当sum[i]==sum[j]时、即k为0时 -> 排除一次自身
unordered_map<int,int> map;
int prev=0;
int count=0;
map[0]=1;//当sum[i] = k时,算一次
int val;
for(auto&e:nums)
{
val=prev+e;
prev+=e;
auto it=map.find(val-k);
if(it!=map.end())
count+=it->second;
map[val]++;
}
return count;
}
};
任务调度器
给你一个用字符数组 tasks 表示的 CPU 需要执行的任务列表。其中每个字母表示一种不同种类的任务。任务可以,以任意顺序执行,并且每个任务都可以在 1 个单位时间内执行完。在任何一个单位时间,CPU 可以完成一个任务,或者处于待命状态。
然而,两个 相同种类 的任务之间必须有长度为整数 n 的冷却时间,因此至少有连续 n 个单位时间内 CPU 在执行不同的任务,或者在待命状态。
你需要计算完成所有任务所需要的 最短时间 。
题解:
class Solution {
public:
int leastInterval(vector<char>& tasks, int n) {
//设有x个桶子,每个桶子执行的时间为(容量) n+1,不同的元素肯定不在同一个桶子里面
//所以最少需要的桶子的个数为最大任务的长度
//如果每个桶子都装满了,则剩余的元素随便插入,如果没装满,则所需时间为 (n+1)*(x-1) + 最后一个桶子剩余的元素
//因为最后一个桶子不需要进行等待
//进行次数的统计
unordered_map<char,int> map;
for(auto&ch:tasks)
{
map[ch]++;
}
//求出最大元素的个数,即桶子的个数
priority_queue<int> heap;
int sum=0;
for(auto&e:map)//创建一个大堆
{
heap.push(e.second);
sum+=e.second;//记录总体元素的个数
}
int max=heap.top();//获得桶子的个数
heap.pop();
sum-=max;//出去最大元素,剩余元素的个数
int time=0;//所需时间
//判断桶子是否装满
if(sum>=max*n)//剩余元素的总量大于所有桶子的总量
{
time=max*(n+1) + sum-max*n;//每个桶子时间 + 剩余元素个数
return time;
}
//此时,剩余元素装不满所有的桶子
int tail=1;
while(!heap.empty()&&heap.top()==max)//取出来的元素个数,和桶子数相等(则一个桶子一个)
{
heap.pop();
tail++;//最后一个桶子的元素
}
sum-=(tail-1)*max;//个数小于桶子个数的元素总量
int num=sum-(max-1)*(n-tail+1);//最后一个桶子可以分配到的元素
time=(max-1)*(n+1) + tail;//桶子时间 + 最后一个桶子所需要的时间
if(num>0)
time+=num;
return time;
}
};
最长连续序列
给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
进阶:你可以设计并实现时间复杂度为 O(n) 的解决方案吗?
题解:
1.将所有的数据加入哈希表中的同时进行去重
2.查找一个连续数组,我们可以从该段数组的最小值 x 开始查询
3.如果x-1不在set之中,说明这个数没有前驱,即这个数是"当前连续数组的最小值",然后用这个数,依次增大在哈希表中进行查找
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
if(nums.size()==0)
return 0;
unordered_set<int> set;
for(auto&e:nums)//将所有数据放入哈希表中
{
set.insert(e);
}
int max_length=0;
int length=0;
for(int i=0;i<nums.size();i++)//找连续的序列
{
if(set.find(nums[i]-1)!=set.end())//有前驱
continue;//跳过
int num=nums[i]+1;
length=1;
while(set.find(num)!=set.end())
{
length++;
num++;
}
max_length=fmax(max_length,length);
}
return max_length;
}
};
以上是关于哈希常见面试题——C++版的主要内容,如果未能解决你的问题,请参考以下文章