【问题标题】:Algorithm: Find index of 2nd smallest element from an unknown array算法:从未知数组中查找第二个最小元素的索引
【发布时间】:2011-04-12 13:41:16
【问题描述】:

我一直在思考我的家庭作业问题。我欢迎(并且更喜欢)任何关于如何解决这个问题的建议或方法。

基本上,我有一个大小为 N 的数组 A。我们不知道元素,但我们知道它们是不同的。我唯一拥有的是一个会在 N 中取两个索引 (i,j) 的人。然后这个人会告诉我 A[j] 是 A[i]。我想通过向这个人提出

【问题讨论】:

  • 那么到目前为止你做了什么?到现在为止,我已经在纸上写了一些小的模糊随机数组,生成了一些 i,j 对并开始解决问题。
  • 我正在考虑随机选择一个数字,然后我会将数组分成大小两部分。我意识到这会改变数组的索引,现在我正在研究如何让元素保持在原来的位置......可能只是移动索引?
  • 可以修改数组吗?或者分配另一个数组并将元素从A 移动到该数组?

标签: algorithm select


【解决方案1】:

这个答案描述了如何找到第二大元素;找到第二小的可以类似地完成。为简单起见,我们还假设所有数字都不同。

为了找到最大的元素,让我们构建一个“冠军”树:将元素配对,决定哪个更大(那个是“赢家”),然后将赢家配对,决定哪个更大,然后以此类推,直到找到“冠军”,这是最大的元素。这需要 n 个步骤。现在,必须将第二大元素与冠军进行比较。 (因为只有冠军才能打败它)。 log n 个元素已与冠军进行比较,因此从这些元素中选择最大的;这需要 log n 步。

作为一个例子,让我们看看这对于数字元组 [6,4,3,5,2,1] 是如何工作的。在第一轮中,对是(6,4),(3,5),(2,1)。获胜者是每对中较大的元素,即 6、5、2。在第二轮对是 (6,5), 2。(2 在这里没有对,所以它会自动升级到下一轮)。第二轮的获胜者是 6 和 2,第三轮唯一的一对是 (6,2),6 是获胜者。现在,通过配对元素并选择获胜者,我们构建了一个(有根的,二叉树)树:

这棵树的属性对于节点x 及其子节点y,z 我们有x>=y, x>=z,所以 我们知道最大的元素是顶部(根)的元素。我们还知道第二大元素w 没有到达顶部,所以它在树中有一个父元素。但是它的父元素大于或等于w,所以在树的某个层次上,最大元素的子元素之一是w。 (换句话说,第二大元素只能被最大元素“击败”)。所以我们所要做的就是回到最大元素所走的路径并收集所有直接子元素,我们知道第二大元素在其中。在我们的例子中,这些是元素 2,5,4 。 (一般来说,大约有log n,其中log 表示以2 为底的对数,因为树大约是log n 高。)。从这些元素中,我们使用任何采用log n 步骤的方法选择最大的元素,我们找到了第二大元素。

所有这些都可能让我们想起冠军,其中数字表示每支球队的“好”程度,因此有“冠军树”一词。

【讨论】:

  • n + n/2 + n/4 + ... 不是n 步骤,而是2n
  • @IVlad:在第一轮,你从 n/2 比较开始,而不是 n。
  • 是的,如果我们真的要严格地说,不是 n 而是 n-1
  • @Henrik - 怎么会这样? 1 2 3 4 5 - 比较 1-2、2-3、3-4、4-5,这是 n - 1 比较。 @sandris - 是的,但仍然超过 n + log n
  • @IVlad:不,我相信他的意思是1-2 3-4 5-6 7-8,然后是半决赛和决赛。 n/2 + n/4 +... + 1 因为 n 是 2 的幂是 n-1。当 n 不是这样的幂时,您可以轻松调整。
【解决方案2】:

首先,找到最小的元素。您可以通过 n-1 个比较来做到这一点,即每个元素最多与 log(n) 个其他元素进行比较。现在查看哪些元素已与最小元素进行比较,并找出其中最小的元素。

【讨论】:

  • 你的算法,和我的一样,最坏的情况是 2*n
  • @Ivan:不,不是。和 Sandris 所说的“冠军树”一样,都是 n + log n。
【解决方案3】:
unknown array = a[].
min1 = a[0].              first element.
min2 = 0.                 can equal anything

for(start at 0, until the end, grow by one):
    if(min1 > a[n]):
      min2 = min1.
      min1 = a[n].

return min2.

【讨论】:

  • 只有 n+3 或 n+5 的复杂度
  • 你也应该比较a[min2] < a[n] < a[min1]的情况下的第二个值。
  • 没有理由这样做,只是让它变得更复杂并增加复杂性。
  • 确实,我没这么看!那么你的算法在a = [-5;-4;-3] 上的结果是什么?会是-4吗?还是0?等等...0a 的一部分吗?
  • 这个算法不正确。它取决于序列中最小元素之前出现的第二个最小元素。如果你输入 [1, 3, 2],它会回答 1,而不是正确的答案 2。
【解决方案4】:

传说

S 空间复杂度 T时间复杂度

我是阿纳布·杜塔。我有话说...为什么不去:

1. maintain the elements as a MIN-HEAP array
                       [S = 0, 
                        T = O(n) if optimized <- ignore as its 1 time activity]
2. call deleteMin() 2 times 
                       [T <= h(tree_height) 
                                   - as internally deleteMin() calls shiftDown()]

所以总 T = O(h)

任何人都有解释为什么这不比使用更好

     a. Tournament or
     b. using MAX-HEAP

注意:第 1 步可以讨论空间和时间复杂度。

【讨论】:

    【解决方案5】:

    研究诸如归并排序之类的排序算法,它的最坏情况复杂度为 O(n log n)。告诉你 A[j] > A[i] 是真还是假的“人”显然是一个比较函数。

    合并排序的工作原理是递归地将您的数组分成两个较小的数组,大小是原始数组的一半,然后再次将合并排序算法应用于这些数组。如果您到达只有一个元素的两个数组的最后一步,您要求 person/comparison 函数告诉您如何对这些数组/元素进行排序。从这一步开始,您开始将子数组合并回原来的但现在已排序的数组。

    最后,您可以简单地返回排序数组的第二个元素,这是第二小的。

    【讨论】:

    • 如果我理解正确,OP 不能重新排列数组中的元素。
    • OP 正在寻找 n + log n,而不是 n * log n。
    • n+log n 仅使用二进制比较有点困难(即 n*log n 是比较排序的下限),您不同意吗?
    【解决方案6】:

    解决此类问题的最佳方法通常是“分而治之”。 IE。尝试简化/划分问题,解决更简单的问题,然后看看它是否提供了任何有助于您解决原始问题的见解。如果更简单的问题仍然太难,请尝试进一步简化,等等。

    在这种情况下,您可以先从数组中找到最小的元素。你会怎么做?

    【讨论】:

      【解决方案7】:
      1. 使用 2 个变量 - varSmallest 和 var2ndSmallest
      2. 让人们比较数组中的第一个和第二个值 - 将较小的索引设置为 varSmallest,将另一个设置为 var2ndSmallest
      3. 按顺序获取下一个索引并将其命名为 varIndexToCheck
      4. 比较 varIndexToCheck 和 var2ndSmallest 的值 - 如果 varIndexToCheck 的值大于 var2ndSmallest 的值,则转到第 3 步
      5. 比较 varIndexToCheck 和 varSmallest 的值 - 如果 varIndexToCheck 的值大于 varSmallest 的值,则设置 var2ndSmallest = varIndexToCheck 并转到第 3 步
      6. 否则,设置 var2ndSmallest = varSmallest 和 varSmallest = varIndexToCheck,然后转到第 3 步

      重复直到没有更多索引。之后,结果索引在 var2ndSmallest 变量内,复杂度为 O(n log n)

      【讨论】:

      • 但是这个最坏情况的复杂度大约是 2n; OP 正在寻找 n + log n。
      • 它有 O(n + log n),我相信真正的问题实际上是“找到可以在数组中找到第二个最小元素的 O(n + log n) 算法”,但是OP 想创造一个不可能的故事。
      • OP 想要 n + log n;没有 O()。请注意,O(n + log n) 与 O(n) 相同。
      猜你喜欢
      • 1970-01-01
      • 2021-03-03
      • 1970-01-01
      • 2018-04-22
      • 2019-01-12
      • 1970-01-01
      • 2023-03-11
      • 2019-08-28
      • 1970-01-01
      相关资源
      最近更新 更多