我有一个数组:
["7", "8", "11", "13", "14"]
Run Code Online (Sandbox Code Playgroud)
我想要最接近的次等数(11如果有的话8),或者如果这样的数字不存在,那么最接近的优等数就是11(即13).
saw*_*awa 13
h = ["7", "8", "11", "13", "14"].map(&:to_i).sort.group_by{|e| e <=> 11}
h[-1].last || h[1].first # => 8
Run Code Online (Sandbox Code Playgroud)
Vis*_*hal 12
尝试使用以下最短的方法获取最接近的值
n = 40
a = [20, 30, 45, 50, 56, 60, 64, 80]
a.min_by{|x| (n-x).abs}
Run Code Online (Sandbox Code Playgroud)
解决这个问题的另一种方法:
a = arr.map(&:to_i).sort #=> [7, 8, 11, 13, 14]
a.reverse.find { |e| e < 11 } #=> 8
a.find { |e| e > 11 } #=> 13
Run Code Online (Sandbox Code Playgroud)
由于如果没有对象匹配则find返回nil,因此可以通过以下方式组合最后两行:
a.reverse.find { |e| e < 11 } || a.find { |e| e > 11 }
Run Code Online (Sandbox Code Playgroud)
下面的方法不对数组进行排序,时间复杂度为 O(n),n 是数组的大小。相比之下,对于第一步对数组进行排序的方法,时间复杂度最多为 O(nlog(n))。参考号
为了避免模糊问题的中心元素,我将假设数组包含整数而不是整数的字符串表示形式。在提出解决方案后,我将简要讨论这一点。
def closest(arr, target)
return nil if arr.empty?
arr.min_by { |e| e <= target ? [0, target-e] : [1, e-target] }
end
Run Code Online (Sandbox Code Playgroud)
arr = [11, 7, 13, 8, 11, 14]
Run Code Online (Sandbox Code Playgroud)
closest(arr, 12) #=> 11
closest(arr, 12.5) #=> 11
closest(arr, 11) #=> 11
closest(arr, 4) #=> 7
closest(arr, 7) #=> 7
Run Code Online (Sandbox Code Playgroud)
请注意,数组是通过Array#<=>方法排序的(请参阅文档的第三段),因此,例如,
target = 12
arr.sort_by { |e| e <= target ? [0, target-e] : [1, e-target] }
#=> [11, 11, 8, 7, 13, 14]
Run Code Online (Sandbox Code Playgroud)
因为0 < 1,不大于 的四个元素target构成返回数组的前四个元素 ( [11, 11, 8, 7]),大于 的两个元素target构成最后两个元素 ( [13, 14]),这两个组均按到 的“距离”排序target。该方法不使用sort_by,但它以相同的方式对元素进行排序arr。
[0, target-e]and[1, e-target]可以用[n1, target-e]and代替[n2, e-target],其中n1和n2是 的任何对象n1 <=> n2 #=> -1。例如,n1 = -7和n2 = 42或n1 = 'a'和n2 = 'b'。
如果arr包含整数的字符串表示形式,如问题中所示,则可以首先将数组转换为整数数组,或者按如下方式更改方法。
def closest(arr, target)
return nil if arr.empty?
target_f = target.to_f
arr.min_by do |e|
e_f = e.to_f
e_f <= target_f ? [0, target_f-e_f] : [1, e_f-target_f]
end
end
Run Code Online (Sandbox Code Playgroud)