跳到主要内容

HJ144. 小红书推荐系统

题目描述​

给定小红的搜索记录(分词后的结果),单词出现次数不少于 3 次的即为"关键词"。请按搜索频次从高到低输出所有关键词;频次相同则按字典序升序输出。

输入格式​

一行字符串,仅由小写字母和空格组成。

输出格式​

每行一个关键词,按频次降序、同频字典序升序输出。

示例​

示例 1​

输入:

kou red game red ok who game red karaoke yukari kou red red nani kou can koukou ongakugame game

输出:

red
game
kou

说明: red 出现 4 次,game、kou 各出现 3 次,为关键词;按频次降序、同频字典序升序输出。


解题思路​

第一步:理解问题本质​

把字符串按空格分词,统计每个单词出现次数,过滤出出现不少于 3 次的,再按"频次降序、同频字典序升序"排序输出。

第二步:暴力解法(手写计数 + 排序)​

用一个字典手动统计次数,再对字典项按规则排序。可工作但代码略长。

第三步:优化解法(Counter + 排序)​

Python 的 collections.Counter 一次性完成计数:

cnt = Counter(s.split())
keywords = [(w, c) for w, c in cnt.items() if c >= 3]
keywords.sort(key=lambda x: (-x[1], x[0]))

排序键用 (-频次, 单词),-频次 实现降序,单词默认升序即字典序。

第四步:最终实现​

过滤出次数 >= 3 的单词,按上述排序键排序,逐行输出。


完整代码实现​

算法可视化 · 逐帧回放这道题的代码13 帧 · 录制输入
import sys
from collections import Counter


def solve() -> None:
s = sys.stdin.readline().strip()
words = s.split()
cnt = Counter(words)

# 过滤出现 >= 3 次的单词
keywords = [(w, c) for w, c in cnt.items() if c >= 3]
# 频次降序,同频字典序升序
keywords.sort(key=lambda x: (-x[1], x[0]))

for w, _ in keywords:
print(w)


if __name__ == "__main__":
solve()

示例推演​

以示例 1 为例,分词后统计:

  • red: 4 次
  • game: 3 次
  • kou: 3 次
  • 其余单词(ok、who、karaoke、yukari、nani、can、koukou、ongakugame)均 < 3 次,被过滤。

过滤后的候选:[(red,4), (game,3), (kou,3)]。

按 (-频次, 单词) 排序:

  • red 频次 4 排最前
  • game、kou 频次同为 3,按字典序 game < kou,所以 game 在前

输出顺序:red、game、kou,正确。


复杂度分析​

解法时间复杂度空间复杂度说明
手写计数+排序O(N + U·log U)O(U)U 为不同单词数
Counter+排序O(N + U·log U)O(U)简洁高效

N 为总单词数,U 为去重后的不同单词数


易错点总结​

1. 排序键写反​

要求"频次降序、同频字典序升序",键应为 (-x[1], x[0])。若写成 (x[0], -x[1]) 会变成先按字典序排,错误。

2. 过滤条件写错​

关键词是"出现不少于 3 次",条件是 c >= 3,写成 c > 3 会漏掉恰好 3 次的单词。

3. 输出格式​

每行一个单词,直接用 print(w) 即可,不需要拼接。


扩展思考​

  • 这是经典的"词频统计 + 多关键字排序"问题,可扩展到 Top-K 热门词、TF-IDF 等文本挖掘场景。
  • 若数据量巨大,可用堆维护 Top-K 而非全量排序,将复杂度降为 O(N + U·log K)。

相关题目​

自测​

加载评论中...