2013-04-30 44 views
3

一種可能的方法來檢查,如果從列表中至少一個數字是其他列表中的一個範圍是這樣的:Ruby:最快的方法來測試列表中的任何數字是否在範圍列表中?

# Input example: 
# numbers = [123, 345, 567] 
# ranges =[(1..10), (60..80), (200..400)] 
def is_in(numbers, ranges) 
    numbers.each do |n| 
    ranges.each do |r| 
     return true if r.include?(n) 
    end 
    end 
    false 
end 

什麼是這種情況下每一個最快的方法:

  1. 只有號碼列表大
  2. 只有範圍列表大
  3. 兩者都是大

回答

3

如果您的數組數組很大且有序,則可以使用Ruby 2.0的新二進制搜索方法Array#bsearch來加速範圍覆蓋檢查從O(N)複雜度到O(logN)。

class Range 
    def fast_cover_any?(ordered_arr) 
    lo = first 
    probe = ordered_arr.bsearch {|x| x >= lo} 
    probe && exclude_end? ? probe < last : probe <= last 
    end 
end 

ranges.any? { |r| r.fast_cover_any?(numbers) } 
+0

很好的答案。我想我必須以此爲基準。謝謝。 – fotanus 2013-04-30 21:17:11

+0

@fotanus我注意到你接受了我的答案 - 這是否意味着你做了一個基準並看到了實質性的改進?如果是這樣,我很樂意看到結果,也許你可以用基準結果更新你的問題,並鏈接到基準的要點? – dbenhur 2013-05-02 02:06:55

1
ranges =[(1..10), (60..80), (200..400)] 

numbers = [123, 700, 567] 
numbers.any?{|x| ranges.any? {|y| y.include? x}} #=> false 

numbers = [123, 400, 567] 
numbers.any?{|x| ranges.any? {|y| y.include? x}} #=> true 

使用ordered list

ranges =[(1..10), (60..80), (200..400)] 

numbers = [123, 300, 567] 
p numbers.sort.any?{|y| ranges.sort_by(&:first).bsearch{|x| x.include? y}} #=> true 

numbers = [123, 700, 567] 
p numbers.sort.any?{|y| ranges.sort_by(&:first).bsearch{|x| x.include? y}} #=> false 
+0

您認爲此代碼是快速的嗎? – ElKamina 2013-04-30 20:21:19

+0

@ElKamina如果您有任何提及不快的事情,請點燃。看着OP的代碼,我認爲'any?'和'include?'是更好的選擇。 – 2013-04-30 20:23:45

+0

它看起來最糟糕的情況是你的代碼的複雜度是o(mn)。你能做得更好嗎? – ElKamina 2013-04-30 20:32:42

1

簡單的答案是存放在組織結構中的數據結構中的一個,並搜索另一個列表中的元素。

假設您有兩個列表x和y分別爲長度爲m和n。

若m < < N:排序x和找到在排序列表Y的元素

如果M >> N:排序y和,並在排序列表

如果找到的元素從X他們是相同的大小選擇任何他們進行排序。

如何組織範圍: 使用每個範圍的開始對列表進行排序。如果兩個範圍重疊合並它們。最後,您將獲得根據範圍的開始排序的非重疊範圍列表。

+0

實際上,只要擴展範圍並使用散列,速度會更快,但內存會爆炸。謝謝,那是我正在尋找的更多這樣的答案。讓我們來看看@Priti的紅寶石知識是否有幫助。 – fotanus 2013-04-30 21:15:01

相關問題