题意:给定一些歌词,歌词是一行一行给定的,要出输出出现次数大于2的所有单词,次数一样多的单词归为一组,每组输出长度最长的,否则输出字典序倒数第二的单词。
解法:这题单词的定义实在是模糊,正确做法是把所有的非字母变为空格后再处理。使用map统计单词数量,然后用数组取出来排个序即可。
代码如下:
#include <cstdlib> #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <cctype> #include <string> #include <map> using namespace std; char str[105]; map<string, int>mp; map<string, int>::iterator it; struct word { string w; int cnt; }; word e[1000]; int idx; bool operator < (const word &a, const word &b) { if (a.cnt != b.cnt) { // 出现频率高的放前面 return a.cnt > b.cnt; } else if (a.w.size() != b.w.size()) { // 长度长的放前面 return a.w.size() > b.w.size(); } else { return a.w > b.w; // 字典序大的放前面,要输出倒数第二个单词,如此便输出正数第二个 } } void deal() { char ss[105], *p; int len = strlen(str); for (int i = 0; i < len; ++i) { if (!isalpha(str[i])) { str[i] = ' '; } } p = strtok(str, " "); while (p) { bool flag = true; strcpy(ss, p); len = strlen(ss); for (int i = 0; i < len; ++i) { if (!isalpha(ss[i])) { flag = false; // 表示这不是一个字母 break; } else if (isupper(ss[i])) { ss[i] += 32; // 转化为小写字母 } } if (flag) { ++mp[ss]; } p = strtok(NULL, " "); } } /* 123 3 a a a a a a b b b b b b c c c c c c 3 abab abab abab abab dd dd 3213 2 LIUXU NIHAO LIUXU LIUXU nihao NIHAO nihao */ int main() { int T, N; for (scanf("%d", &T); T; --T) { mp.clear(); idx = 0; scanf("%d", &N), getchar(); for (int i = 0; i < N; ++i) { gets(str); deal(); } for (it = mp.begin(); it != mp.end(); ++it) { if (it->second >= 2) { e[idx].w = it->first; e[idx++].cnt = it->second; } } sort(e, e+idx); e[idx].cnt = 0; // 防止最后一个单词误判 int last = 0, first = 1; for (int i = 0; i < idx; ++i) { if (e[i].cnt != last) { int k = i; if (e[i].cnt == e[i+1].cnt && e[i].w.size() == e[i+1].w.size()) ++k; if (first) { printf("%s", e[k].w.c_str()); first = 0; } else { printf(" %s", e[k].w.c_str()); } } last = e[i].cnt; } puts(""); } return 0; }