C++经典面试题打卡
Posted ych9527
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++经典面试题打卡相关的知识,希望对你有一定的参考价值。
传递信息
小朋友 A 在和 ta 的小伙伴们玩传信息游戏,游戏规则如下:
有 n 名玩家,所有玩家编号分别为 0 ~ n-1,其中小朋友 A 的编号为 0
每个玩家都有固定的若干个可传信息的其他玩家(也可能没有)。传信息的关系是单向的(比如 A 可以向 B 传信息,但 B 不能向 A 传信息)。
每轮信息必须需要传递给另一个人,且信息可重复经过同一个人
给定总玩家数 n,以及按 [玩家编号,对应可传递玩家编号] 关系组成的二维数组 relation。返回信息从小 A (编号 0 ) 经过 k 轮传递到编号为 n-1 的小伙伴处的方案数;若不能到达,返回 0。
题解1:dfs
-
由题可知,是求路径总和问题,即每一步可以到达多个位置,利用递归属性,遍历这个位置
-
递归出口:a.当前步伐数超过k,立即终止;b.当前步伐数=k,且编号=n-1
class Solution { public: void _numWays(int n,vector<vector<int>>& relation,int k,int code,int count,int &ret) { if(count>k) return; if(count==k&&code==n-1) { ret++; return; } for(auto&e:relation) { if(e[0]==code) _numWays(n,relation,k,e[1],count+1,ret); } } int numWays(int n, vector<vector<int>>& relation, int k) { //从0处传到n-1处,的所有路径总和数 int code=0;//当前的编号 int count=0;//记录当前步伐 int ret=0;//记录路径总和 _numWays(n,relation,k,code,count,ret); return ret; } };
题解2:动态规划
- 设dp[i][j]表示第i轮,传递给编号为j的方案数
- 对dp进行初始化,显然第0轮的时候,起始位置为dp[0][0] -> dp[0][0]=1,其余位置都为0
- 转移方程的构建:设当前方案编号为des,到达des的编号为scr -> dp[i][des]+=dp[i-1][scr]
class Solution {
public:
int numWays(int n, vector<vector<int>>& relation, int k)
{
//dp[i][j]表示第i轮,传递给编号j的方案数
vector<vector<int>>dp(k+1,vector<int>(n,0));
dp[0][0]=1;
for(int i=0;i<k;i++)//控制轮数
{
for(auto&e:relation)
{
int scr=e[0];//从哪里来
int des=e[1];//去往哪里
dp[i+1][des]+=dp[i][scr];
}
}
return dp[k][n-1];
}
};
大餐计数
大餐 是指 恰好包含两道不同餐品 的一餐,其美味程度之和等于 2 的幂。你可以搭配 任意 两道餐品做一顿大餐。给你一个整数数组 deliciousness ,其中 deliciousness[i] 是第 i 道餐品的美味程度,返回你可以用数组中的餐品做出的不同 大餐 的数量。结果需要对 109 + 7 取余。注意,只要餐品下标不同,就可以认为是不同的餐品,即便它们的美味程度相同。
1 <= deliciousness.length <= 105
0 <= deliciousness[i] <= 2^20
题解:
- 由题可知任意两数之和的范围在[1,2^21]
- 在统计的时候,只需要从数组中拿出来一个数,在循环得到2的[0,21]的幂,然后进行相减,就可以得到另外一个数,是多少
- 得到另外一个数后,就可以取数组中进行查找
- 这时,我们在遍历的过程之中,可以将数加入map之中进行统计出现过的次数,为了防止重复查找,我们可以先查找这个数是否在map之中,然后再将数组中的元素添加至map之
class Solution {
public:
int countPairs(vector<int>& deliciousness) {
int div=pow(10,9)+7;
//两数之和的范围为: [0,2^21]
unordered_map<int,int> mp;
int count=0;
for(auto&e:deliciousness)
{
for(int i=0;i<22;i++)
{
int val=pow(2,i) - e;//得到另外一个数
if(mp.find(val)!=mp.end())
{
count=(count+mp[val])%div;
}
}
mp[e]++;//统计所有数字出现的次数
}
return count;
}
};
和相同的二元子数组
- 将数组的前缀和存入哈希表中
- val = 一个连续的子数组后- goal,如果val在哈希表中,则加上对应数值
class Solution {
public:
int numSubarraysWithSum(vector<int>& nums, int goal) {
int count=0;
unordered_map<int,int>mp;
int sum=0;
for(auto&e:nums)
{
mp[sum]++;
sum+=e;
count+=mp[sum-goal];
}
return count;
}
};
基于时间的键值存储
创建一个基于时间的键值存储类 TimeMap,它支持下面两个操作:
-
set(string key, string value, int timestamp)存储键 key、值 value,以及给定的时间戳 timestamp。
-
get(string key, int timestamp)返回先前调用 set(key, value, timestamp_prev) 所存储的值,其中 timestamp_prev <= timestamp。如果有多个这样的值,则返回对应最大的 timestamp_prev 的那个值。如果没有值,则返回空字符串("")。
题解:
- 构建一个 unordered_map<string,vector<pair<int,string>>> mp,存储三个元素
- 由于是按时间戳进行存储的,因此vector里面的元素天然有序
- 在取出来的时候,利用二分法进行判断
class TimeMap {
public:
/** Initialize your data structure here. */
TimeMap() {}
void set(string key, string value, int timestamp) {
tp.first=timestamp;
tp.second=value;
mp[key].push_back(tp);
}
int BinarySearch(vector<pair<int,string>>&arr,int &time)
{
int left=0;
int right=arr.size()-1;
while(left<=right)
{
int mid=left+(right-left)/2;
if(arr[mid].first>time)
right=mid-1;
else if(arr[mid].first<time)
left=mid+1;
else
return mid;
}
return right;
}
string get(string key, int timestamp) {
if(mp[key].size()==0||mp[key][0].first>timestamp)
return "";
//由于是按时间顺序插入的,因此arr里面的元素是按时间排好序的
//找到对应的位置,前面一个位置就是需要找的值
int mid= BinarySearch(mp[key],timestamp);
if(mid>=0)
{
string ret=mp[key][mid].second;
return ret;
}
return "";
}
unordered_map<string,vector<pair<int,string>>> mp;
pair<int,string> tp;
};
以上是关于C++经典面试题打卡的主要内容,如果未能解决你的问题,请参考以下文章