如何返回数组中的第三大数

Posted

技术标签:

【中文标题】如何返回数组中的第三大数【英文标题】:How to return the third largest number in an array 【发布时间】:2017-06-12 06:12:00 【问题描述】:

我回答编程问题的代码逻辑是:

    在输入数组中找出最大的数。 将该数字存储在一个新数组中。 从输入数组中删除该数字。 重复 # 的 1-3 直到新数组中有三个元素。 选择要返回的数组的最后一个元素。

我的代码返回三个 10,而不是数组中的三个最大元素 10、8 和 4。我认为这可能是因为一旦内部 while 循环完成,代码就无法返回它?

我的测试代码是:

puts(third_greatest([8, 1, 10, 4])).to_s

我的代码是:

def third_greatest(nums)
  greatest_number = nil
  three_greatest = []

  three_greatest_idx = 0

  while three_greatest_idx < 3
    number_idx = 0

    while number_idx < nums.length
      current_number = nums[number_idx]

      if greatest_number == nil
        greatest_number = current_number
      elsif greatest_number < current_number
        greatest_number = current_number
      end

      number_idx += 1
    end

    three_greatest.unshift(greatest_number)
    nums.delete(greatest_number)
    three_greatest_idx += 1
  end

  return three_greatest
end

【问题讨论】:

你是如何处理重复的? 这个问题实际上是this question的副本。 【参考方案1】:

对其进行排序并使用 Ruby 对数组的负索引选项。

[8, 1, 10, 4].sort[-3]
>> 4

编辑:经过多次测试,我确定上面显示的排序方法比下面的方法更快,如果在 m 元素的数组中搜索第 n 个最大数时,n > m 大小的 1/20。由于在您的示例中,我们正在寻找 4 个元素的数组中的第三大数字,并且 3 比 0.2 大得多,所以上面的答案比这种替代方法更有效:

[8, 1, 10, 4].max(3)[-1]
>> 4

【讨论】:

它可以工作,但是为了找到 3 个元素而对整个数组进行排序是多余的。 当然,使用 3 元素数组,很难编写低效的排序算法。不过,您的排序适用于 N 个元素。 见@theTinMan 回答。 使用 5 个元素数组时,sortmax 的执行速度几乎无法使用 Benchmark 进行注册,并且反弹速度最快,因此使用其中一个并不重要。在 500 个元素时,max 几乎没有更快,但它是一致的。 如果有的话,我会追求 Ruby 金色徽章。我不在乎 cmets。我确实认为 *** 是一个学习的好地方,而且我个人真的很喜欢得到建设性的批评。当有人告诉我我写的东西不是最佳的时,我不会个人认为。我试图理解为什么并在下次做得更好。我不是故意要冒犯你的。我的评论只是告诉你,如果有 100 个元素(这似乎是合理的),那么对 97 个最小的元素进行排序是没有意义的。真的没有必要侮辱任何人。【参考方案2】:

只是为了帮助人们了解maxsort 和不使用内置方法之间的性能差异:

require 'fruity'

ary = (1..100).to_a.shuffle

def use_max(a)
  a.max(3).last
end

def use_sort(a)
  a.sort[-3]
end

def nth_greatest(nums, n)
  nums = nums.dup # prevent mutating the original array
  result = nil
  n.times do
    idx, max = -1, -Float::INFINITY
    nums.length.times do |i|
      idx, max = [i - 1, nums[i - 1]] if nums[i - 1] > max
    end
    result = nums.delete_at idx
  end
  result
end

compare do
  sorted  use_sort(ary) 
  maxed   use_max(ary) 
  nth_greatested  nth_greatest(ary, 3) 
end

# >> Running each test 512 times. Test will take about 1 second.
# >> sorted is faster than maxed by 2x ± 0.1
# >> maxed is faster than nth_greatested by 3x ± 0.1

增加数组的大小:

ary = (1..1_000).to_a.shuffle

结果:

# >> Running each test 64 times. Test will take about 1 second.
# >> maxed is faster than sorted by 80.0% ± 10.0%
# >> sorted is faster than nth_greatested by 3x ± 0.1

然后再次增加数组大小:

ary = (1..10_000).to_a.shuffle

结果:

# >> Running each test 8 times. Test will take about 1 second.
# >> maxed is faster than sorted by 3x ± 0.1
# >> sorted is faster than nth_greatested by 2x ± 0.1

文档没有提到 max(3) 是否返回一个反向排序的数组,即使它看起来很像。

文档示例是:

a.max(2) #=> ["horse", "dog"]

这是递减的,但这不是一个很好的例子,因为使用数字更容易看到:

ary.max(3) # => [100, 99, 98]

以下是使用 Benchmark 显示基线速度的一些结果:

require 'benchmark'

ary = (1..5).to_a.shuffle

10.times do
  Benchmark.bm(4) do |b|
    b.report('sort')  ary.sort[-3] 
    b.report('max')  ary.max(3).last 
  end
end

# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000010)
# >> max    0.000000   0.000000   0.000000 (  0.000006)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000003)
# >> max    0.000000   0.000000   0.000000 (  0.000004)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000003)
# >> max    0.000000   0.000000   0.000000 (  0.000004)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000003)
# >> max    0.000000   0.000000   0.000000 (  0.000003)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000003)
# >> max    0.000000   0.000000   0.000000 (  0.000004)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000003)
# >> max    0.000000   0.000000   0.000000 (  0.000004)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000005)
# >> max    0.000000   0.000000   0.000000 (  0.000005)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000003)
# >> max    0.000000   0.000000   0.000000 (  0.000004)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000003)
# >> max    0.000000   0.000000   0.000000 (  0.000003)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000003)
# >> max    0.000000   0.000000   0.000000 (  0.000003)

并增加数组的大小:

ary = (1..100).to_a.shuffle

# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000020)
# >> max    0.000000   0.000000   0.000000 (  0.000013)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000013)
# >> max    0.000000   0.000000   0.000000 (  0.000011)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000010)
# >> max    0.000000   0.000000   0.000000 (  0.000010)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000009)
# >> max    0.000000   0.000000   0.000000 (  0.000010)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000009)
# >> max    0.000000   0.000000   0.000000 (  0.000010)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000008)
# >> max    0.000000   0.000000   0.000000 (  0.000010)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000008)
# >> max    0.000000   0.000000   0.000000 (  0.000010)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000008)
# >> max    0.000000   0.000000   0.000000 (  0.000013)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000011)
# >> max    0.000000   0.000000   0.000000 (  0.000010)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000008)
# >> max    0.000000   0.000000   0.000000 (  0.000010)

还有:

ary = (1..1_000).to_a.shuffle

# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000110)
# >> max    0.000000   0.000000   0.000000 (  0.000057)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000103)
# >> max    0.000000   0.000000   0.000000 (  0.000054)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000101)
# >> max    0.000000   0.000000   0.000000 (  0.000053)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000100)
# >> max    0.000000   0.000000   0.000000 (  0.000053)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000100)
# >> max    0.000000   0.000000   0.000000 (  0.000053)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000100)
# >> max    0.000000   0.000000   0.000000 (  0.000056)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000099)
# >> max    0.000000   0.000000   0.000000 (  0.000053)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000099)
# >> max    0.000000   0.000000   0.000000 (  0.000053)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000100)
# >> max    0.000000   0.000000   0.000000 (  0.000053)
# >>            user     system      total        real
# >> sort   0.000000   0.000000   0.000000 (  0.000099)
# >> max    0.000000   0.000000   0.000000 (  0.000053)

【讨论】:

documentation 没有提到max(3) 是否返回一个反向排序的数组,即使它看起来很像。 确实如此,你是对的,文档并不清楚。 这是code。它会在返回之前对max(n) 进行排序。 我认为您已经超出了此处答案的要求。肯定赞成。看看我的理论是否正确会很有趣,如果你在 100 个值数组中寻找第 95 个最大值,那么差异也可以忽略不计。 我大部分时间都在使用 Fruity,但有时我需要 Benchmark 提供的详细信息。您可以在答案中看到两者。如果您在 SO 中搜索我的用户 ID 和“fruity”或“benchmark”,您会发现很多情况。【参考方案3】:

你忘记取消设置greatest_number

  nums.delete(greatest_number)
  three_greatest_idx += 1
  greatest_number = nil # this line
end

显然,Ruby 中有一个非常简单的解决方案,但我想当然地认为你想自己做。

【讨论】:

哈哈,是的,我确实想自己做,因为(如您所知)我是 Ruby 新手。非常感谢,你太棒了!【参考方案4】:

我认为这是一项可能不允许大量使用 Enumerable 模块的任务。仍然有更简单的方法。例如。您不需要维护另一个数组:只需从原始数组中删除最高 N 次:

def nth_greatest(nums, n)
  nums = nums.dup # prevent mutating the original array
  result = nil
  n.times do
    idx, max = -1, -Float::INFINITY
    nums.length.times do |i|
      idx, max = [i - 1, nums[i - 1]] if nums[i - 1] > max
    end
    result = nums.delete_at idx
  end
  result
end

nth_greatest [8, 1, 10, 4], 2
#⇒ 8
nth_greatest [8, 1, 10, 4], 3
#⇒ 4

【讨论】:

对所有解决方案进行基准测试会很有趣。我想知道具有 3 个变量的 1-pass 解决方案会是什么样子。不过,我今天在 SO 上花了足够的时间。 :)【参考方案5】:

一旦你开始考虑用 Ruby 的方式解决这样的问题,我的意思是更多地依赖 Enumerable 并将你的意图表达为一系列简单的操作,通常链接在一起,那么解决方案就会变得更容易找到.

例如,要在任意数组中找到三个最高的数字,显而易见的解决方案可能是这样的:

def three_greatest(list)
  list.sort.reverse.first(3)
end

对列表进行排序,默认情况下从最低到最高,然后将其反转,使其从最高到最低。最后一个操作是复制前三个整体。这似乎很合理,因为它非常清楚地表达了您的意图并且效果很好。

问题是,如果您更仔细地查看 Enumerable 产品,使用max 会发现更简单的解决方案:

def three_greatest(list)
  list.max(3)
end

这里要吸取的教训是,Enumerable 库与机械师的工具箱不同,它拥有大量有用的工具。花一些时间至少阅读其中的内容很重要,这样您就不会浪费时间重新发明已经以优雅形式存在的东西。

换句话说,在解决问题时,检查该问题是否已经解决。在许多情况下,您会发现有一种工具可以完全满足您的需求。

【讨论】:

不错。我从来没有注意到 max 的可选参数。 非常中肯的建议,谢谢。我肯定会在解决下一个问题时检查。我正在审查问题的程序给了我一组有限的 Ruby 信息,因为他们声称这是我完成他们的编码挑战所需要知道的全部内容。但你是对的,我不应该限制自己,开始更多地探索 Ruby 的世界。再次,非常感谢! 顺便说一句,你需要list.max(3).last 来回答这个问题。 ^ 这个。这是一个很棒的帖子,请给出答案。 @Eric,可选参数是在 Ruby v2.2 中添加的。 minmin_bymax_by 也知道了。

以上是关于如何返回数组中的第三大数的主要内容,如果未能解决你的问题,请参考以下文章

414-第三大的数

5855. 找出数组中的第 K 大整数

返回整数数组最大子数组之和

返回一个在 mongoDB 中有一个数组的字段,并返回该数组中的第一个和最后一个值

Leetcode练习(python):第414题:第三大的数:给定一个非空数组,返回此数组中第三大的数。如果不存在,则返回数组中最大的数。要求算法时间复杂度必须是O(n)。

Leetcode练习(python):第414题:第三大的数:给定一个非空数组,返回此数组中第三大的数。如果不存在,则返回数组中最大的数。要求算法时间复杂度必须是O(n)。