华为4.6机考凉经
总的来说华子这两道题只是输入输出在处理的时候麻烦一点,思路倒是很直白,过程是有点复杂,要做好心理准备去一道一道啃下来,不然像这次第一题嫌麻烦跳第二道题,第二道题又没做出来,就GG。而且通过此次机考,发现我自己做题状态与平时完全不同,思维有点凝滞,应该是太紧张了,所以说多多参加机考还是有用的。加油,再接再厉!
T1 热词排序
T1 题干
有多篇文章输入,每篇文章分为标题行和正文行,每篇文章输入时标题和正文各占一行。需要统计所有文章中出现的热词并输出topN的热词。title中的词权重为3,text中权重为1,所有文章中的热词权重相加即为该词的总权重。排序方法为:
- 两词权重大的排前面
- 若权重一样,则在title中最先出现的排前面
- 若title中出现顺序一样,则在text中最先出现的排前面
测试案例:
3 2 xinguan feiyan xinzeng bendi quezhen anli ju baodao chengdu xinzeng xinguan feiyan bendi quezhen anli yili shenzhen xinzeng bendi quezhen anli liangli yi***gti kongzhi lianghao xinguan yimiao linchuang shiyan wuzhong xinguan yimiao tongguo sanqi linchaung shiyan xiaoguo lianghao
输出:
//忘记了
注意:第一行两数代表topN和文章总数M,后面每两行代表一篇文章
T1 解析
此题非常直观,思路是哈希表+sort排序,但是值得注意的是有多重排序条件,我们应该如何进行处理?
此处我们需要自定义一个cmp函数用于比较,由于条件太多,可以设置一个类,用于存储该词的权重,在title中首次出现的index,在text中首次出现的index,这样只需要使用一个自定义的类的cmp函数就可以进行多重条件的排序。
代码如下:
#include <iostream>
#include<vector>
#include<string>
#include<unordered_map>
#include<algorithm>
#include<sstream>
using namespace std;
//自定义类
struct Data
{
string word;
int total_cnt=0;
int title_index = INT_MAX;
int text_index = INT_MAX;
};
//自定义cmp函数
bool cmp(Data& a, Data& b)
{
if (a.total_cnt == b.total_cnt)
{
if (a.title_index == b.title_index)
return a.text_index < b.text_index;
else
return a.title_index < b.title_index;
}
else
return a.total_cnt > b.total_cnt;
}
/// <summary>
/// 按照pattern拆分字符串,若patter间没有字符串,则不会加入到结果中
/// </summary>
/// <param name="str"></param>
/// <param name="pattern"></param>
/// <returns></returns>
vector<string> split(string& str, const char pattern)
{
vector<string> ans;
string temp;
stringstream ss(str);
while (getline(ss, temp, pattern))
{
ans.push_back(temp);
}
return ans;
}
int main()
{
vector<string> title, text;
unordered_map<string,Data> mp;
int topN = 0, M = 0;
scanf_s("%d %d\n", &topN,&M);
for (int i = 0; i < M; ++i)
{
string temp1, temp2;
getline(cin, temp1);
getline(cin, temp2);
title.push_back(temp1);
text.push_back(temp2);
//生成每个字段的Data对象并计算其权重和首次出现的下标信息
vector<string> ss = split(temp1,' ');
for (int j = 0;j<ss.size();++j)
{
string s = ss[j];
if (mp.find(s) == mp.end())
mp.insert(make_pair(s, Data()));
Data& d = mp[s];
d.word = s;
d.total_cnt += 3;
if (d.title_index > j) d.title_index = j;
}
ss = split(temp2, ' ');
for (int j = 0; j < ss.size(); ++j)
{
string s = ss[j];
if (mp.find(s) == mp.end())
mp.insert(make_pair(s, Data()));
Data& d = mp[s];
d.word = s;
d.total_cnt += 1;
if (d.text_index > j) d.text_index = j;
}
temp1.clear();
temp2.clear();
}
vector<Data> vec;
for (auto& p : mp)
{
vec.push_back(p.second);
}
//对所有Data对象进行排序
sort(vec.begin(), vec.end(), cmp);
//调整输入输出格式
string ans;
for (int i = 0; i < topN; ++i)
{
ans += vec[i].word;
ans.push_back(' ');
}
//注意去掉结尾的空格
ans.pop_back();
cout << ans;
return 0;
} T1 复盘易错点
-
本题最恶心的是输入输出,对于经常刷leetcode的人很不习惯。本题如果第一行用两个输入输出则会在第一行留下一个 ’\n’,之后循环读取会先读取这个’\n’,再读取之后的文章行。可以用getline处理掉这个换行符,或者用 scanf_s("%d %d\n", &topN,&M)进行格式化读取,注意里面有个’\n’。
我对输入输出还是不够熟练,之后还是要多做相关的练习。做了一点输入输出的小总结:
https://youthful-gastonia-a60.notion.site/c198b82749e94edf8b9bec440b819666
-
本题中还有一个关键的问题就是多重条件下的排序,可以自己建立一个类,写一个类的比较函数进行排序。由于之前没有做过这方面的习题,所以没往这方面想,一股脑想着直接排序,想破脑袋也想不出好的方法。吃一堑长一智,这种题型记住了。
本题的cmp函数写起来还是有些需要注意的点的,总结如下:
https://youthful-gastonia-a60.notion.site/cmp-81a18ebf03da41abaec6c4a7ea3bcad0
T2 依赖关系
T2 题干
某段程序依赖于其他的程序启动,题目提供了n个程序(0~n-1)以及他们之间的依赖关系,要求按下标顺序返回target程序所有前置依赖项。若依赖关系中有环存在,则该程序不能启动,返回-1;若该程序没有依赖关系,则不用管它。
其中,第一行为程序个数n,第二行为target程序下标,之后的第 i 行表示第 i 个程序的相关依赖信息。
对于依赖信息的这一行,第一个数表示依赖个数,之后的数用逗号隔开,每个数表示其依赖程序的下标
测试案例:
4 2 0 1,0 1,1 2,0,2
答输出:
0 1
解析:
依赖关系如图:
程序2依赖程序1,程序1依赖于程序0,所以按序输出为: 0 1
T2 解析
这是一道典型的拓扑关系,解决此类问题可以用dfs和bfs。由于该题只要输出某个节点的前置依赖节点,不妨使用dfs。
程序如下:
#include <iostream>
#include<vector>
#include<string>
#include<sstream>
using namespace std;
/// <summary>
/// 按照pattern拆分字符串,若patter间没有字符串,则不会加入到结果中
/// </summary>
/// <param name="str"></param>
/// <param name="pattern"></param>
/// <returns></returns>
vector<string> split(string& str, const char pattern)
{
vector<string> ans;
string temp;
stringstream ss(str);
while (getline(ss, temp, pattern))
{
ans.push_back(temp);
}
return ans;
}
bool dfs(vector<vector<int>>& edges, vector<int>& visited, int node)
{
//若该节点已经完成了访问,则可以剪枝
if (visited[node] == 1) return true;
//若该节点处于正在访问状态,说明该路径下有环
else if (visited[node] == 0) return false;
//将节点状态设置为正在访问
visited[node] = 0;
//依次遍历该节点下的所有依赖项,看看是否有相互依赖的情况发生
for (auto& i : edges[node])
{
if (!dfs(edges, visited, i)) return false;
}
//若所有依赖项都完成了访问,则设置本节点为完成访问状态
visited[node] = 1;
return true;
}
int main()
{
int n, index;
cin >> n >> index;
//edges存储节点i对应的所有前置依赖节点
vector<vector<int>> edges(n);
//visited存储每个节点的访问状态,-1表示未访问,0表示正在访问,1表示访问完成
vector<int> visited(n, -1);
//换行
string temp;
getline(cin, temp);
//逐行获取edges依赖关系
for (int i = 0; i < n; ++i)
{
temp.clear();
getline(cin, temp);
vector<string> ss = split(temp, ',');
int num = atoi(ss[0].c_str());
for (int j = 1; j <= num; ++j)
{
edges[i].push_back(atoi(ss[j].c_str()));
}
}
string ans;
//如果有环,则返回-1
if (!dfs(edges, visited, index)) cout << -1;
else
{
//循环读取以访问的节点(不包括index节点)
for (int i = 0; i < n; ++i)
{
if (visited[i] == 1 && i != index) {
ans += to_string(i);
ans.push_back(' ');
}
}
ans.pop_back();
cout << ans;
}
return 0;
} T2 复盘易错点
-
在做题的时候想到了用dfs,但是之前很少接触过拓扑关系的题,所以不知道如何判断是否有环,之后可以对拓扑关系的题做一下总结。
https://youthful-gastonia-a60.notion.site/9ccc89716579426385a572b92784c59e
-
华子的输入输出很恶心,我觉得可以记住一些通用的输入输出处理函数(或预先在本地IDE中写好),比如split函数,这样处理起来方便很多。
T3 接雨水
此题我没时间看,听说与接雨水类似,之后再总结一下
#华为笔试##实习##笔试题目#