leetcode
leetcode 151 ~ 200
统计词频

统计词频

难度:

标签:

题目描述

写一个 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

说明:

  • 不要担心词频相同的单词的排序问题,每个单词出现的频率都是唯一的。
  • 你可以使用一行 Unix pipes 实现吗?

代码结果

运行时间: 0 ms, 内存: 3.7 MB


/*
 * 思路:
 * 1. 读取文件内容并按空格拆分成单词。
 * 2. 使用流操作和Collectors计算每个单词的出现次数。
 * 3. 使用流排序并输出结果。
 */
import java.io.*;
import java.nio.file.*;
import java.util.*;
import java.util.stream.*;
 
public class WordFrequencyStream {
    public static void main(String[] args) throws IOException {
        List<String> lines = Files.readAllLines(Paths.get("words.txt"));
        lines.stream()
                .flatMap(line -> Arrays.stream(line.split("\s+")))
                .collect(Collectors.groupingBy(word -> word, Collectors.counting()))
                .entrySet()
                .stream()
                .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
                .forEach(e -> System.out.println(e.getKey() + " " + e.getValue()));
    }
}

解释

方法:

该题解使用了Unix管道和一系列命令来统计文本文件中单词的频率。具体步骤如下: 1. 使用`cat`命令读取文件内容 2. 使用`tr`命令将所有空格字符替换为换行符,这样每个单词就会独占一行 3. 使用`sort -r`命令按字典序反向排序所有单词 4. 使用`uniq -c`命令统计每个单词出现的次数,并在每行行首显示频次 5. 使用`sort -r`命令按频次由高到低排序 6. 使用`awk`命令调整输出格式,使其符合题目要求

时间复杂度:

平均情况:O(nlogn),最坏情况:O(n^2)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么在处理单词时选择使用`tr -s " " "\n"`命令将空格替换为换行符?这样做有什么具体的好处吗?
使用`tr -s " " "\n"`命令将空格替换为换行符的主要好处是可以将每个单词分隔开来,使每个单词单独占据一行。这样做的好处是便于后续的单词计数和排序处理。此外,`tr -s`命令中的`-s`选项会压缩源文本中连续的空格成为一个换行符,这有助于处理文本中可能存在的多余空格,确保单词之间的分隔更为准确。
🦆
在使用`sort -r`进行字典序反向排序之前,为什么不直接进行词频统计?排序这一步的目的是什么?
在进行词频统计之前使用`sort -r`进行字典序反向排序是为了确保相同的单词能够相邻出现,这是因为`uniq -c`命令只能对相邻的重复行进行计数。如果不先排序,相同的单词可能会散布在文件的不同部分,导致`uniq -c`无法正确统计其出现次数。因此,排序是为了数据的正确整理,确保统计的准确性。
🦆
在统计单词频率时,`uniq -c`命令是如何确保正确计数的?这是否意味着输入必须先排序?
`uniq -c`命令通过计算连续重复行的数量来统计频率,因此前提是所有重复的行必须是相邻的。这确实意味着在使用`uniq -c`之前,输入数据必须经过排序,以便所有相同的单词排列在一起。如果没有预先排序,`uniq -c`将无法正确统计分散在文本中的相同单词的出现次数。
🦆
您提到的第二次使用`sort -r`来按频次排序,是否存在更高效的排序方法考虑到`uniq -c`已经提供了部分组织好的数据?
虽然`uniq -c`提供了按单词出现频次的部分组织好的数据,但这些数据是按单词的出现顺序而非频次排序的。因此,需要第二次使用`sort -r`来按频次进行排序。如果考虑效率优化,可以考虑使用`sort -nr`,即按数值进行逆序排序,这通常比按文本逆序排序更快,因为它直接对数字进行比较。

相关问题

前 K 个高频元素

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

 

示例 1:

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

示例 2:

输入: nums = [1], k = 1
输出: [1]

 

提示:

  • 1 <= nums.length <= 105
  • k 的取值范围是 [1, 数组中不相同的元素的个数]
  • 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的

 

进阶:你所设计算法的时间复杂度 必须 优于 O(n log n) ,其中 n 是数组大小。