华为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 接雨水
此题我没时间看,听说与接雨水类似,之后再总结一下
#华为笔试##实习##笔试题目#