【问题标题】:Computing the mode (most frequent element) of a set in linear time?在线性时间内计算集合的模式(最频繁的元素)?
【发布时间】:2011-05-09 06:59:40
【问题描述】:

在 Skiena 的“算法设计手册”一书中,计算集合的 众数(最常见元素),据说有一个 Ω(n log n) 下限(这让我很困惑),而且(我猜对了)没有更快的最坏情况算法来计算模式。我只是对 Ω(n log n) 的下限感到困惑。

查看本书页面Google Books

但在某些情况下,这肯定可以在线性时间内计算(最佳情况),例如通过如下 Java 代码(在字符串中查找最常见的字符),“技巧”是使用哈希表计算出现次数。这似乎很明显。

那么,我对这个问题的理解缺少什么?

编辑:(谜团已解决)正如 StriplingWarrior 指出的那样,如果仅使用比较,即不使用内存索引,则下限成立,另请参阅:http://en.wikipedia.org/wiki/Element_distinctness_problem

// Linear time
char computeMode(String input) {
  // initialize currentMode to first char
  char[] chars = input.toCharArray();
  char currentMode = chars[0];
  int currentModeCount = 0;
  HashMap<Character, Integer> counts = new HashMap<Character, Integer>();
  for(char character : chars) {
    int count = putget(counts, character); // occurences so far
    // test whether character should be the new currentMode
    if(count > currentModeCount) {
      currentMode = character;
      currentModeCount = count; // also save the count
    }
  }
  return currentMode;
}

// Constant time
int putget(HashMap<Character, Integer> map, char character) {
  if(!map.containsKey(character)) {
    // if character not seen before, initialize to zero
    map.put(character, 0);
  }
 // increment
  int newValue = map.get(character) + 1;
  map.put(character, newValue);
  return newValue;
}

【问题讨论】:

  • 勘误表中似乎没有提及:cs.sunysb.edu/~skiena/algorist/book/errata
  • 无法读取页面。一些古怪的信息,显然是丹麦语。
  • 把 google.dk 改成 google.com,就可以了。
  • 修复了指向 google.com 的链接 :)
  • 别管哈希图,它们会因为可疑的复杂性声明而分散注意力。考虑在仅由“0”和“1”组成的序列中找到最频繁元素的问题。 显然这是线性时间,只需计算事物(同样您可以按线性时间对它们进行排序,最简单的桶排序情况)。正如 StriplingWarrior 所说,具有此界限的是问题的比较版本,就像 comparison 排序具有 Big_Omega(n log n) 下限一样。大概当本书更早地定义其术语时,它以某种方式限制了讨论。

标签: algorithm mode manual


【解决方案1】:

作者似乎将他的逻辑建立在 comparison 是您唯一可用的操作的假设之上。使用基于哈希的数据结构 某种 可以通过将大多数情况中需要进行比较的可能性降低到您基本上可以在恒定时间内进行比较的程度来解决这个问题.

但是,如果精心挑选的数字总是会产生哈希冲突,那么您最终会有效地将哈希集变成一个列表,这会使您的算法变成 O(n²)。正如作者指出的那样,首先将值简单地排序到一个列表中提供了最好的保证算法,尽管在大多数情况下哈希集更可取。

【讨论】:

  • @Skipperkongen:作者在谈到寻找模式时实际上使用了 Big-O 表示法。他说“没有比 O(n log n) 算法更快的最坏情况算法来计算众数”,我们知道这一点因为测试集合中唯一性的问题可以证明为有一个 Ω(n log n) 下限。
  • 我接受最佳保证算法是 O(n log n)。但是您是否同意元素唯一性具有 Omega(n log n) 下限是不正确的?
  • 元素区别的维基页面实际上提到了“代数计算树模型”的界限,它禁止使用元素来索引内存...en.wikipedia.org/wiki/Element_distinctness_problem
  • 所以你说它是正确的,假设比较是唯一可用的操作:)这让我感到困惑,因为这通常是你在实践中所做的,即索引内存:)
  • @Skipperkongen:是的,维基百科的那篇文章很好地说明了问题的复杂性有 Θ(n log n) 作为上限和下限,除非你知道一些特定的数据可以让你像桶排序这样的优化。
【解决方案2】:

那么,我对这个问题的理解缺少什么?

在许多特定情况下,数组或哈希表就足够了。在“一般情况下”它不会,因为哈希表访问并不总是恒定的时间。

为了保证恒定的时间访问,您必须能够保证每个 bin 中可能最终出现的键的数量受某个常数的限制。对于字符来说,这相当容易,但如果集合元素是双精度或字符串,则不会(除了纯学术意义上的,例如有限数量的双精度值)。

【讨论】:

    【解决方案3】:

    哈希表查找是摊销的常数时间,即通常查找 n 个随机键的总成本是 O(n)。在最坏的情况下,它们可能是线性的。因此,虽然通常它们可以将模式计算的阶数降低到 O(n),但在最坏的情况下,它会将模式计算的阶增加到 O(n^2)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-08
      • 2021-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多