如果n是两个数组中较小者的大小,则以下方法首先计算n每个数组的所有长度序列,然后确定第一个数组中也出现在第二个数组中的那些序列。这种公共序列的数量显然为零或一(后者是因为至少有一个数组的大小为n)。如果有一个公共的长度序列,n我们返回一个包含该单个序列的数组,我们就完成了。
如果没有共同的长度序列,n我们对长度序列重复该过程n - 1。如果公共长度序列的数组n - 1非空,我们返回该数组并完成;否则我们重复长度的序列n - 2,依此类推。nil如果没有长度的公共序列,则返回1。
代码
def longest_common_sequences(arr1, arr2)
[arr1.size, arr2.size].min.downto(0).each do |n|
break nil if n.zero?
common = sequences_by_length(arr1, n) & sequences_by_length(arr2, n)
break common unless common.empty?
end
end
def sequences_by_length(arr, n)
arr.each_cons(n).to_a
end
例子
longest_common_sequences [1,2,2,3,4], [5,2,2,3,6]
#=> [[2, 2, 3]]
longest_common_sequences [2,2,3,3,5], [3,3,2,2,5]
#=> [[2, 2], [3, 3]]
longest_common_sequences [1,2,3], [4,5,6]
#=> nil
解释
我在puts的正文中添加了语句,longest_common_sequences以说明上述第二个示例的方法执行的计算。
arr1 = [2,2,3,3,5]
arr2 = [3,3,2,2,5]
t = [arr1.size, arr2.size].min
puts "[arr1.size, arr2.size].min = #{t}"
t.downto(0).each do |n|
puts "n = #{n}"
puts "break nil as #{n}.zero? #=> true" if n.zero?
break nil if n.zero?
common = sequences_by_length(arr1, n) & sequences_by_length(arr2, n)
puts "common = #{common}"
break common unless common.empty?
end
def sequences_by_length(arr, n)
puts " generate sequences of length #{n} for arr = #{arr}"
a = arr.each_cons(n).to_a
puts " returning #{a}"
a
end
印刷
n = 5
generate sequences of length 5 for arr = [2, 2, 3, 3, 5]
returning [[2, 2, 3, 3, 5]]
generate sequences of length 5 for arr = [3, 3, 2, 2, 5]
returning [[3, 3, 2, 2, 5]]
common = []
n = 4
generate sequences of length 4 for arr = [2, 2, 3, 3, 5]
returning [[2, 2, 3, 3], [2, 3, 3, 5]]
generate sequences of length 4 for arr = [3, 3, 2, 2, 5]
returning [[3, 3, 2, 2], [3, 2, 2, 5]]
common = []
n = 3
generate sequences of length 3 for arr = [2, 2, 3, 3, 5]
returning [[2, 2, 3], [2, 3, 3], [3, 3, 5]]
generate sequences of length 3 for arr = [3, 3, 2, 2, 5]
returning [[3, 3, 2], [3, 2, 2], [2, 2, 5]]
common = []
n = 2
generate sequences of length 2 for arr = [2, 2, 3, 3, 5]
returning [[2, 2], [2, 3], [3, 3], [3, 5]]
generate sequences of length 2 for arr = [3, 3, 2, 2, 5]
returning [[3, 3], [3, 2], [2, 2], [2, 5]]
common = [[2, 2], [3, 3]]
作为common.empty? #=> false,[[2, 2], [3, 3]]返回。