[20, 32, 32, 21, 30, 25, 29, 13, 14].min(2)
# => [13, 20]
为什么不是[13, 14]
?以及做我得到了什么,两个最小的元素(线性时间)?
The doc的句子“如果给出n参数,最少n个元素作为数组返回”对我来说不是很清楚,但我认为它是{{ 1}}应该给我最小的两个元素。我找不到太多关于它的内容,但是this thread,它可能是起源,似乎与我同意,并说它应该返回与min(2)
相同,但它不会:
sort.first(n)
对不起,如果对“大”的例子感到愚蠢和抱歉,但已经减少了 - 删除一个号码(13或14除外)确实给了我[20, 32, 32, 21, 30, 25, 29, 13, 14].sort.first(2)
# => [13, 14]
。
答案 0 :(得分:8)
我刚刚发布了Ruby Issue Tracking System中的错误说明:
我想我发现了这个问题。举个例子:
[20, 32, 32, 21, 30, 25, 29, 13, 14].min(2)
这将调用函数" nmin_run"在文件" enum.c"中,哪个 套装" bufmax"到我们想要的最小数量(n)的4倍(对于 例如,bufmax是8),然后在行中 1327会致电 功能" nmin_i"对于原始数组的每个元素。
在函数" nmin_i"中,当缓冲区已满(" data-> curlen == data-> bufmax"),函数" nmin_filter"叫做。在这个例子中, 当curlen为8时会发生这种情况,因此缓冲区为[20,32,32,21, 30,25,29,13]。 " nmin_filter"会做快速的直到n 到目前为止,最小的元素位于缓冲区的最左边部分,并且 将丢弃剩余的元素,这使我们[20,13] 在缓冲区。
现在开始出现问题。在" nmin_filter"结束时极限 (显然是为了存储最大的价值 buffer)设置为缓冲区中的最后一个值(在示例中为13), 这不是真的。然后根据该值" nmin_i"将丢弃 所有剩余的元素都大于该值(在示例中,丢弃 14)。然后对缓冲区进行排序并返回:
[13, 20]
因此,解决方案是删除所有与限制相关的部分,或者采取 最后一个支点作为限制。
答案 1 :(得分:2)
顺便说一下,回答你的问题......
怎么做我得到了我想要的东西,两个最小的元素(线性时间)?
如果此方法不存在或同时它被破坏,您可以使用Quickselect在线性时间中选择两个最小元素,这基本上是Ruby在min
中所做的工作。
以下是我对维基百科的直接翻译:
class Array
def mymin(n)
return self.sort if self.size <= n
a = self.dup
left = 0
right = a.size - 1
loop do
pivot_index = left + (right - left) / 2;
pivot_value = a[pivot_index]
a[pivot_index], a[right] = a[right], a[pivot_index]
store_index = left
left.upto(right - 1).each do |i|
if a[i] < pivot_value
a[store_index], a[i] = a[i], a[store_index]
store_index += 1
end
end
a[right], a[store_index] = a[store_index], a[right]
if n - 1 == store_index
break
elsif n - 1 < store_index
right = store_index - 1
else
left = store_index + 1
end
end
a.take(n).sort
end
end
然后我们尝试你的例子:
[20, 32, 32, 21, 30, 25, 29, 13, 14].mymin(2)
# => [13, 14]
耶!我们刚刚修正了min
。但请注意,此实现的空间复杂度与原始数组的大小呈线性关系,而Ruby实现与值n
呈线性关系。此外,如果您的原始数组有太多重复项,这将有一个糟糕的性能,你应该寻找
3路分区。
如果你只想要n = 2的min
并且真的担心性能,那么可以为O(L)
保证{(1}}的情况制作优化版本(假设为L
是数组的长度。)
class Array
def min2
m1 = nil
m2 = nil
self.each do |x|
if m1.nil? || x < m1
m2 = m1
m1 = x
elsif m2.nil? || x < m2
m2 = x
end
end
[m1, m2].compact
end
end
以类似的方式使用它:
[20, 32, 32, 21, 30, 25, 29, 13, 14].min2
# => [13, 14]