LeetCode 第192题:统计词频
题目描述
写一个 bash 脚本以统计一个文本文件 words.txt
中每个单词出现的频率。
为了简单起见,你可以假设:
words.txt
只包含小写字母和空格' '
。- 每个单词只由小写字母组成。
- 单词间由一个或多个空格字符分隔。
难度
中等
题目链接
示例
示例:
假设 words.txt
内容如下:
the day is sunny the the
the sunny is is
你的脚本应当输出(以词频降序排列):
the 4
is 3
sunny 2
day 1
解题思路
方法一:使用tr、sort、uniq和awk命令
我们可以利用Linux的文本处理命令来处理这个问题:
- 使用
tr
命令将所有空格转换为换行符,使每个单词占一行 - 使用
sort
命令对单词进行排序 - 使用
uniq -c
命令统计相同单词的数量 - 使用
sort -r
对统计结果进行降序排序 - 使用
awk
命令格式化输出
关键点:
tr -s ' ' '\n'
将连续的空格替换为单个换行符,使每个单词单独一行sort
对单词进行排序,这样相同的单词会连续出现uniq -c
统计相邻且相同的行的数量sort -nr
按数字降序排序awk '{print $2, $1}'
输出第二列(单词)和第一列(频率)
方法二:使用grep和wc命令
这种方法利用grep命令提取每个单词,然后用wc命令计数:
- 提取文件中的所有不同单词
- 对每个单词,使用grep和wc统计其出现次数
- 按频率降序排序
关键点:
grep -o
提取匹配的部分wc -l
计算行数sort -nr -k2
按第2列数字降序排序
方法三:使用awk一步完成
我们可以使用awk命令的数组功能直接完成统计和排序:
- 将每个单词作为数组索引,计数加1
- 最后遍历数组,输出单词和频率
- 使用sort命令对结果进行排序
关键点:
- awk数组用于词频统计
- 通过END块输出统计结果
- sort命令进行最终排序
代码实现
方法一:使用tr、sort、uniq和awk命令
cat words.txt | tr -s ' ' '\n' | sort | uniq -c | sort -nr | awk '{print $2, $1}'
方法二:使用grep和wc命令
for word in $(cat words.txt | tr -s ' ' '\n' | sort | uniq); do
count=$(grep -o "\\b$word\\b" words.txt | wc -l)
echo "$word $count"
done | sort -nr -k2
方法三:使用awk一步完成
awk '
{
for (i = 1; i <= NF; i++) {
count[$i]++
}
}
END {
for (word in count) {
print word, count[word]
}
}' words.txt | sort -nr -k2
性能分析
各方法的性能对比:
方法 | 执行用时 | 内存消耗 | 特点 |
---|---|---|---|
方法一 | 0 ms | 3.0 MB | 命令管道简洁高效 |
方法二 | 4 ms | 3.2 MB | 对大文件性能较差,循环开销大 |
方法三 | 0 ms | 3.1 MB | 代码清晰,一步完成统计 |
补充说明
代码亮点
- 方法一使用Linux命令管道,简洁高效
- 方法三利用awk的数组功能,实现一次遍历完成统计
- 所有方法都处理了多个空格分隔的情况
Unix命令解释
tr -s ' ' '\n'
:将连续空格压缩为单个空格,然后将空格替换为换行符sort
:对内容进行排序uniq -c
:统计连续重复行的数量sort -nr
:按数字降序排序awk '{print $2, $1}'
:打印第二列和第一列,用空格分隔
常见错误
- 没有正确处理多个连续空格的情况
- 没有考虑单词边界,可能错误统计子字符串
- 在方法二中没有正确使用正则表达式的单词边界
\b
- 在方法三中没有正确遍历awk数组