跳转至

BISHI23 小红书推荐系统

简单通过率 67.81%python3样例通过牛客 AC哈希排序

牛客原题  源码

讲解章节字典自定义排序哈希与字符串哈希

一句话

统计出现次数 >= 3 的单词,按频次降序、同频字典序升序输出。

解题思路

这题考什么

词频统计的标准套路:哈希计数 + 多关键字排序。 单词是不定长字符串,没法直接当数组下标,所以用哈希表把「单词 -> 次数」记下来。 collections.Counter 就是专门做计数的字典子类,构造时传入一个可迭代对象, 它会一次遍历统计出每个元素的出现次数。

排序键一次给全 (-次数, 单词):元组比较先比第一项,次数取负即为「频次从高到低」; 第一项相等时再比单词本身,得到「同频按字典序升序」。

这里全程用 bytes 而不解码成 str:read().split() 切出来的本来就是 bytes, 比较 bytes 等价于逐字节比较 ASCII 码,对「仅含小写字母」的输入来说, 与字符串字典序完全一致;只在最后拼输出时才对入选的少数单词 decode, 省掉了对全部单词做解码的开销。

数据规模与复杂度

串长 <= 1e5,单词数上界同量级。计数 O(L);设不同单词数为 k, 排序 O(k log k)。总体 O(L + k log k),在 2 秒时限下余量很大。

坑在哪

  1. 题面说输入是「一行含空格的字符串」,但既然只按空格切词, read().split() 就够了——它会把换行和连续空格一并吃掉, 不必先 readline 再 strip,也不会切出空串。
  2. 判定是「不少于 3 次」,即 c >= 3;写成 c > 3 会漏掉恰好出现 3 次的词, 样例里的 kou 正好出现 3 次。
  3. 排序键一次给全,而不是「先按字典序排一遍、再按次数排一遍」。 后者靠 Python 排序的稳定性也能得到正确结果,但依赖了一个不显然的性质, 还要多排一趟。
  4. 只输出关键词本身,一行一个,不输出次数。

样例复核

red 出现 4 次、game 3 次、kou 3 次,其余均不足 3 次; 按 (-次数, 单词) 排序得 red(4) < game(3) < kou(3),与样例输出一致。

参考实现

solutions/BISHI23.py
1
2
3
4
5
6
7
8
9
import sys
from collections import Counter

# 按空白切词并计数;元素是 bytes,省掉全量 decode
cnt = Counter(sys.stdin.buffer.read().split())
# 排序键 (-次数, 单词):频次降序在前,同频时按字节序(等价于字典序)升序
res = sorted(((-c, w) for w, c in cnt.items() if c >= 3))
# 一次性写出,避免逐行 print 的多次系统调用
sys.stdout.write("".join(w.decode() + "\n" for _, w in res))
[:octicons-arrow-left-16: BISHI22](BISHI22.md) [BISHI24 :octicons-arrow-right-16:](BISHI24.md)