【问题标题】:Efficient Algorithm (Hashing, Sorting) [closed]高效算法(散列、排序)[关闭]
【发布时间】:2013-10-05 02:00:01
【问题描述】:

我遇到了以下问题 - 我收到了一个文本文件,其中包含大量允许重复的单词。我需要编写一个算法,以降序输出出现频率最多的 1000 个单词。这是一个例子

**input.txt**

aa aa bb cc bb bb bb dd dd

**output.txt** (note - frequencies can be repeated)

bb 4
aa 2
dd 2
cc 1
  1. 这是我解决此问题的方法。首先读取所有的单词并将它们存储在HashMap中,以word为key。这样做的最终结果是我拥有了所有单词及其频率。

  2. 现在我遍历 HashMap 并为每个键值对创建一个对象 {word, frequency} 然后我将它插入到 SortedSet 中(我为此编写了一个比较器)。

  3. 现在我只需遍历 SortedSet 1000 次即可获得结果。

我想知道解决这个问题的更好方法。

谢谢

【问题讨论】:

  • 非常正确,我也会这样做。
  • 见:stackoverflow.com/questions/185697/…,最值得注意的是他们使用堆。
  • 谢谢威廉。该链接看起来很有用。
  • 您是否尝试过 Java 教程 Freq.java 中已提供的答案,详细说明已给出 here。我希望这是你想要的:-)

标签: java algorithm sorting hashmap


【解决方案1】:

让我们关注第 2 步和第 3 步。假设有 N 个单词,每个单词都有给定的频率,并且您必须找到前 K(在您的情况下为 1000)。

您的方法运行时间为 O(N log N)。正如斯蒂芬所说,这已经足够了:)无论如何,这里有一些可能的改进。

第一种方法:正如链接中所建议的,您可以使用最小堆(您可以使用优先级队列)来维护前 1000 个。实现起来并不难。一旦你有了带有频率的地图,就开始对其进行迭代。如果最小堆的大小小于 K,则继续推动该对(单词,频率)。如果堆的大小为 K,则比较当前条目从映射到堆根的频率(堆中的最低频率)。如果新频率较低,请忽略它。如果它更高,则从堆中弹出最低的并推送当前的。这种方法将在 O(N log K) 中运行。

第二种方法: selection algorithm 在 O(N) 中找到列表(未排序)中的第 K_th 个最大(或最小)数。您可以找到第 K_th 最大的,然后遍历地图以得到小于或等于 K 的所有内容。如果超过 K,则必须是第 K_th 最大的数字重复很多次的情况。如果你跟踪它,你可以删除这个数字所需的计数来获得前 K。这需要 O(N)。

第三种方法:您可以执行随机快速排序的变体来找到前 K。我认为,预期的运行时间是 O(N)。

【讨论】:

  • 感谢 M K 的帮助。
【解决方案2】:

有没有更好的方法来解决这个问题?

有两种方式来看待这个......取决于你所说的“更好”。

如果“更好”的意思是“使用更少的时间和/或内存”,那么根据问题的规模和您可用的资源,有可能解决这个问题的方法。例如:

  • 如果文本文件(或多个文件)大到足以证明这一点,您可以考虑将问题分区以在多处理器上运行。但这不是直截了当的......如果问题太小,分区的开销实际上可能会使解决方案变慢!

  • 链接的问答描述了一种可能加快步骤 2 和 3 的方法。问题是,如果您对代码进行基准测试,您可能会发现步骤 1 是大部分 CPU 时间花费的地方。 (而且输入文件越大,效果可能越明显……)

如果“更好”意味着“更快地解决问题”,那么答案是“可能不会”。假设您有一个您描述的算法的良好实现版本,那么为(可能)更快的更复杂算法所付出的努力可能不值得。

计算机时间比软件开发时间便宜!


我的建议是执行以下操作:

  1. 对现有程序进行基准测试。它在真实的输入文件上运行得足够快吗?如果“是”,则调用程序完成。

  2. 分析您现有程序在实际输入文件上运行的情况。分析是否显示任何明显的性能热点?有代码调优的机会吗?如果“是”,请尝试它们,然后重复基准测试步骤,看看它们是否真的有帮助。

  3. 查看 GC 日志。是否有迹象表明您的代码具有过多的 GC 开销?如果“是”,请查看一些简单的 GC 调整(如增加堆大小)是否会产生影响。

如果您在完成上述所有操作后仍未获得可接受的性能,那么现在是开始寻找替代算法的时候了。

【讨论】:

  • 谢谢斯蒂芬。我已经测试了它的大小文件,而且速度很快。然而,在我解决这个问题之前——我花了 0.5 小时考虑优先级队列,但后来我放弃了。上面提到的方法很容易实现,所以目前我会坚持下去。是的,“计算机时间比软件开发时间便宜!”这是真的:-)
  • @VVV - 足够快就足够好了 :-)
  • 实际上这是我迄今为止最快的速度:-)。感谢您的详细描述。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-14
相关资源
最近更新 更多