如何返回数组中的第三大数
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 个元素数组时,sort
和 max
的执行速度几乎无法使用 Benchmark 进行注册,并且反弹速度最快,因此使用其中一个并不重要。在 500 个元素时,max
几乎没有更快,但它是一致的。
如果有的话,我会追求 Ruby 金色徽章。我不在乎 cmets。我确实认为 *** 是一个学习的好地方,而且我个人真的很喜欢得到建设性的批评。当有人告诉我我写的东西不是最佳的时,我不会个人认为。我试图理解为什么并在下次做得更好。我不是故意要冒犯你的。我的评论只是告诉你,如果有 100 个元素(这似乎是合理的),那么对 97 个最小的元素进行排序是没有意义的。真的没有必要侮辱任何人。【参考方案2】:
只是为了帮助人们了解max
、sort
和不使用内置方法之间的性能差异:
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 中添加的。 min
、min_by
和 max_by
也知道了。以上是关于如何返回数组中的第三大数的主要内容,如果未能解决你的问题,请参考以下文章
返回一个在 mongoDB 中有一个数组的字段,并返回该数组中的第一个和最后一个值
Leetcode练习(python):第414题:第三大的数:给定一个非空数组,返回此数组中第三大的数。如果不存在,则返回数组中最大的数。要求算法时间复杂度必须是O(n)。
Leetcode练习(python):第414题:第三大的数:给定一个非空数组,返回此数组中第三大的数。如果不存在,则返回数组中最大的数。要求算法时间复杂度必须是O(n)。