使用Ruby查找数组数组中增长最长的序列

时间:2014-08-10 05:41:03

标签: ruby arrays nested sequence

我有一个包含整数的数组。例如:

arr=[[109, 160, 184, 229],
[45, 67, 158, 175, 201, 250, 273],
[33, 86, 89, 182, 245, 251, 254, 272],
[35, 76, 93, 143, 222, 267],
[189, 242],
[19],
[41, 58, 135, 256],
[59],
[60, 138, 183, 203, 246],
[45, 67, 158, 175, 197, 201, 250, 273],
[55, 57, 101, 103, 193, 212, 231, 257],
[18, 23, 51, 75, 106, 139, 179, 247],
[31, 72, 92, 99, 148, 230],
[128, 142, 151, 164, 170, 173, 196, 226],
[15],
[4],
[41, 113, 135, 256],
[33, 251]]

在这里查看整个示例数组http://pastebin.com/exzi8Mnq

每个嵌套数组都是排序的,包含uniqe元素,没有重复,它们至少包含一个元素,最多没有限制(通常最多10-15个元素)和200-2000个嵌套数组。

我想找到整个数组中整数的最长序列,哪些元素单调增长,没有相等性。例如,来自第一个数组的一个元素,第二个来自第二个数组,等等。每个嵌套数组应该只提供一个元素或零。也许第一个元素不是来自第一个数组,而是第二个,或第三个或更多,以确保最终生长最长的序列。最重要的是,可以跳过一些嵌套数组,我的意思是它们不会为结果序列提供任何元素。

您可以想象一个数字系统中的一个looong数,其基数等于最大嵌套数组的大小,数字可以指代嵌套数组,因此我们可以计算所有可能的序列。例如,0123表示从第二个数组中选择第一个元素的序列,其索引是0(1-1)。第二个元素从第3个数组中选择,其索引是2(3-1)第一个数字0表示没有从第一个数组中选择整数。允许的最大数字值受给定嵌套数组的大小限制。

输出示例:[45,86,93,189] 第一个元素是从第二个数组中选择的,第二个是从第三个数组中选择的。然而,这显然不是可以提取的最长序列。

我认为某种类型的回溯或将所有数组的产品创建到枚举器并检查结果。

我的副标题计时程序需要这种方法。

3 个答案:

答案 0 :(得分:1)

所以这很有趣。

#!/usr/bin/env ruby

a = [ [109, 160, 184, 229], [45, 67, 158, 175, 201, 250, 273], [33, 86, 89, 182, 245, 251, 254, 272], [35, 76, 93, 143, 222, 267], [189, 242], [19], [41, 58, 135, 256], [59], [60, 138, 183, 203, 246], [45, 67, 158, 175, 197, 201, 250, 273], [55, 57, 101, 103, 193, 212, 231, 257], [18, 23, 51, 75, 106, 139, 179, 247], [31, 72, 92, 99, 148, 230], [128, 142, 151, 164, 170, 173, 196, 226], [15], [4], [41, 113, 135, 256], [33, 251], [25, 69, 84, 97, 133, 171, 204, 248, 252, 258, 268, 269], [25, 69, 96, 133, 171, 176, 194, 204, 252, 258, 268], [17, 29, 53, 61, 102, 104, 123, 127, 129, 145, 146, 178, 188, 233, 265], [6, 13, 39, 71, 98, 105, 185, 234, 235], [86, 89, 181, 182, 245, 254, 272], [50, 108, 110, 222], [55, 101, 103, 169, 191, 193, 205, 212, 231], [56, 83, 134, 138, 246], [109, 160, 184, 229], [208], [60, 138, 183, 203, 246], [45, 67, 158, 175, 201, 250, 273], [266], [161], [100, 228], [38, 82, 115, 180, 255, 260], [116], [13, 57, 98, 105, 185, 235, 257], [113, 135], [30, 131, 202, 241, 271], [266], [46, 52, 198, 209, 232], [125, 130, 154], [161], [92, 99, 148, 230], [12, 37, 49, 80, 94, 151, 164, 226], [26, 102, 126, 127, 145, 236, 261], [20, 37, 80, 132, 219, 259], [95, 227], [113, 135], [38, 82, 115, 180, 255, 260], [149], [263], [163], [17, 53, 61, 104, 128, 129, 142, 170, 173, 196, 233, 265], [120, 220], [31, 72, 92, 99, 148, 230], [56, 83, 134, 138, 246], [4, 109], [128, 142, 151, 164, 170, 173, 196, 226], [46, 52, 174, 199, 209], [120, 220], [25, 69, 96, 133, 171, 176, 194, 204, 252, 258, 268], [177], [17, 29, 53, 61, 104, 123, 128, 129, 142, 146, 178, 188, 196, 233, 265], [47, 107], [60, 161, 183, 203], [56, 83, 134, 138, 246], [100, 109, 160, 184, 228, 229], [174, 199], [187], [3, 11, 62, 153, 165, 216], [18, 20, 139, 247, 259], [9, 21, 74, 157], [54, 85, 210, 211], [25, 69, 84, 97, 133, 171, 204, 248, 252, 258, 268, 269], [41, 58, 135, 256], [54, 85, 210], [198, 232], [46, 52, 174, 199, 209], [48, 119, 200], [45, 120, 197, 250, 273], [1], [198, 232], [47, 107], [35, 76, 93, 143, 222, 267], [218], [13, 55, 57, 98, 101, 193, 212, 231, 235, 257], [4, 109], [41, 58, 256], [31, 92, 99, 148, 230], [35, 76, 93, 143, 222, 267], [35, 93, 124], [31, 72, 92, 99, 148, 230], [243], [12, 49, 94, 151, 164, 170, 173, 226], [18, 23, 51, 75, 106, 139, 179, 247], [6, 39, 71, 75, 105, 106, 185, 234], [30, 131, 202, 241, 271], [18, 20, 139, 247, 259], [20, 37, 80, 132, 219, 259], [35, 76, 93, 143, 222, 267], [31, 72, 92, 99, 148, 230], [30, 131, 202, 241, 271], [46, 52, 199, 209], [46, 52, 198, 209, 232], [17, 53, 61, 104, 128, 129, 142, 170, 173, 196, 233, 265], [125, 266], [31, 72, 84, 97, 248, 269], [227], [33, 86, 182, 245, 251, 254], [35, 93, 124], [76, 108, 143, 222, 267], [17, 53, 61, 104, 128, 129, 142, 170, 173, 196, 233, 265], [31, 72, 84, 97, 248, 269] ]

def find_longest_seq(a, l = [[]], i = nil, s = nil)
  s ||= a.size - 1
  if (set = a[s])
    if set.size > 0
      set.sort!
      recursed = false
      while (e = set.last)
        if i.nil? or e < i
          l, r = find_longest_seq(a, l, e, s - 1)
          r = r ? r + [e] : [e]
          if r.size == l.first.size
            l << r
          elsif r.size > l.first.size
            l = [r]
          end
          return [l, r]
        elsif not recursed
          l, r = find_longest_seq(a, l, e, s - 1)
          r = r ? r + [e] : [e]
          if r.size == l.first.size
            l << r
          elsif r.size > l.first.size
            l = [r]
          end
          recursed = true
        end
        set.pop
      end
    end
  end
  [l, nil]
end

l, r = find_longest_seq(a.map(&:clone))
l.each { |e| puts e.inspect }
如果数据已经排序,

.sort!是可选的。

输出:

[20, 132, 143, 148, 202, 209, 232, 265, 266, 269]
[18, 80, 93, 99, 131, 209, 232, 265, 266, 269]

答案 1 :(得分:1)

<强>方法

我们可以使用动态编程来解决这个问题,其中:

  • 阶段是子阵列;
  • 状态变量是序列中最大的元素;
  • 每个阶段i0 <= i < arr.size,每个n0 <= n <= largest最大化的功能(其中largest是所有arr.flatten.max中最大的值子阵列:arr[0],...arr[i]),是为了最大化从n取得的最长序列的长度,这样序列的最大(最后)值为arr[j], j=0..arr.size-1

不熟悉&#34;动态编程&#34;?如果是这样,不是问题,因为这里的优化技术是直截了当的。

我们将依次检查每个子阵列j。对于每个n和每个0 <= n <= largestlargest = arr.flatten.maxlongest[n]),我们将数组arr[0]定义为从子数组中抽取的所有序列中最长的序列{ {1}},arr[1],... arr[j],其最大(最后)值最多为n。在检查了所有子阵列后,longest[largest]给出了最优解。是的,这是一个满口的,但如果你想了解我使用的算法,你需要了解我刚才所说的。

<强>代码

def find_longest_sequence(arr)
  largest = arr.map(&:last).max
  longest = Array.new(largest+1,[])
  arr.each do |a|
    new_longest = a.each_with_object([]) { |n,new_longest|
      # See if, by using n from a, we have found a largest sequence ending in n
      (new_longest << [n,longest[n-1]+[n]]) if
        longest[n].size <= longest[n-1].size }
    # Update longest for each pair in new_longest, starting from largest n
    until new_longest.empty?
      i,seq = new_longest.pop
      len = seq.size
      (i..largest).each { |j|
        (len > longest[j].size) ? (longest[j] = seq) : break }
    end
  end
  longest[-1]
end

<强>实施例

arr = [[3, 4], [2, 5], [1, 4], [4, 5]]
find_longest_sequence(arr) #=> [3, 4, 5]

对于上面的数组arr

find_longest_sequence(arr)
  #=> [33, 35, 58, 59, 60, 67, 103, 139, 148, 226, 256]

对于您提供的link数组arr

find_longest_sequence(arr)
  #=> [ 33,  35,  58,  59,  60,  67,  75,  92,  97, 104, 105,
  #    108, 109, 115, 116, 125, 127, 132, 135, 149, 163, 170,
  #    173, 174, 176, 177, 178, 183, 184, 187, 198, 199, 200,
  #    218, 222, 230, 234, 241, 247, 259, 265, 266, 267, 269]
find_longest_sequence(arr).size #=> 44

<强>解释

解释算法如何工作的最佳方法可能是使用一些调试语句来运行它。

def find_longest_sequence(arr)
  largest = arr.map(&:last).max
  longest = Array.new(largest+1,[])
  puts "largest = #{largest}, longest.size = #{longest.size}"
  arr.each do |a|
    new_longest = a.each_with_object([]) { |n,new_longest|
      # See if, by using n from a, we have found a largest sequence ending in n
      (new_longest << [n,longest[n-1]+[n]]) if
        longest[n].size <= longest[n-1].size }
      puts "  new_longest = #{new_longest}"
    # Update longest for each pair in new_longest, starting from largest n
    until new_longest.empty?
      i,seq = new_longest.pop
      len = seq.size
      puts "    i=#{i}, seq=#{seq}, len =#{len}, new_longest=#{new_longest}"
      (i..largest).each { |j| (len > longest[j].size) ?
        (puts "j=#{j}"; longest[j] = seq) : break }
      puts "    longest=#{longest}"
    end
  end
  longest[-1]
end

arr = [[3, 4], [2, 5], [1, 4], [4, 5]]
find_longest_sequence(arr) #=> [3, 4, 5]

[[3, 4], [2, 5], [1, 4], [4, 5]]
largest = 5, longest.size = 6
  new_longest = [[3, [3]], [4, [4]]]
    i=4, seq=[4], len =1, new_longest=[[3, [3]]]
j=4
j=5
    longest=[[], [], [], [], [4], [4]]
    i=3, seq=[3], len =1, new_longest=[]
j=3
    longest=[[], [], [], [3], [4], [4]]
  new_longest = [[2, [2]], [5, [4, 5]]]
    i=5, seq=[4, 5], len =2, new_longest=[[2, [2]]]
j=5
    longest=[[], [], [], [3], [4], [4, 5]]
    i=2, seq=[2], len =1, new_longest=[]
j=2
    longest=[[], [], [2], [3], [4], [4, 5]]
  new_longest = [[1, [1]], [4, [3, 4]]]
    i=4, seq=[3, 4], len =2, new_longest=[[1, [1]]]
j=4
    longest=[[], [], [2], [3], [3, 4], [4, 5]]
    i=1, seq=[1], len =1, new_longest=[]
j=1
    longest=[[], [1], [2], [3], [3, 4], [4, 5]]
  new_longest = [[5, [3, 4, 5]]]
    i=5, seq=[3, 4, 5], len =3, new_longest=[]
j=5
    longest=[[], [1], [2], [3], [3, 4], [3, 4, 5]]
[3, 4, 5]

答案 2 :(得分:0)

不是那么容易,在某些情况下,可以跳过数组以获得更好的结果。无论如何,这是一个天真的实现,贪婪地采用下一个更大的数字。

[编辑] :当选择序列中的下一个更大的数字时,算法现在会运行跳过数组的所有可能排列。现在保证算法会返回最佳解决方案。

require 'pp'

@arr=[[109, 160, 184, 229],[45, 67, 158, 175, 201, 250, 273],[33, 86, 89, 182, 245, 251, 254, 272],[35, 76, 93, 143, 222, 267],[189, 242],[19],[41, 58, 135, 256],[59],[60, 138, 183, 203, 246],[45, 67, 158, 175, 197, 201, 250, 273],[55, 57, 101, 103, 193, 212, 231, 257],[18, 23, 51, 75, 106, 139, 179, 247],[31, 72, 92, 99, 148, 230],[128, 142, 151, 164, 170, 173, 196, 226],[15],[4],[41, 113, 135, 256],[33, 251]]

@result_set =[]
reverse_ary = []

@perms = [1, 0].repeated_permutation(@arr.size).to_a

def iterate_large_ary(perm)
    seq = []
    @arr.each_with_index do |a,i| 
        if perm[i] != 0
            if seq.length == 0
                seq << a[0]
            else
                temp = find_next_bigger_number(a,seq[-1])
                if temp != nil
                 seq << temp
                end
            end
        else
            next
        end         
    end 
    @result_set << [seq,seq.length]
end 

def find_next_bigger_number(ary,num)
    temp = nil
    ary.each do |el|

        if el > num
            temp = el
            break
        end 
    end
    return temp
end 

@perms.each{|perm| iterate_large_ary(perm)}

pp @result_set.sort!{|a,b| b[1] <=> a[1]}[0][0]