【问题标题】:Finding the longest growing sequence in an array of arrays with Ruby使用 Ruby 在数组数组中查找最长的增长序列
【发布时间】:2014-10-03 06:08:28
【问题描述】:

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

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

每个嵌套数组都经过排序,并且包含唯一的元素,没有重复,它们至少包含一个元素,最多没有限制(通常最多 10-15 个元素),总共 200-2000 个嵌套数组。

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

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

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

我认为某种回溯或创建所有数组的乘积到枚举器并检查结果。

我的字幕计时程序需要这个方法。

【问题讨论】:

  • 您能添加一个所需输出的示例吗?
  • 这个问题要么是微不足道的(展平数组、做 uniq 和排序),要么是不清楚。
  • 示例输出:[45, 86, 93, 189] 第一个元素是从第二个数组中选择的,第二个是从第三个数组中选择的,等等。但这显然不是可以提取的最长序列。
  • @Konstantin - 到目前为止你能分享你的解决方案吗?
  • 假设最长序列的元素之一来自arr[j]。我是否正确假设最长序列的下一个元素必须来自数组arr[k]k >= j 之一?请通过编辑澄清这一点。如果不是这样,问题就很简单了。

标签: ruby arrays nested sequence


【解决方案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]

【讨论】:

  • @UriAgassi 是的,我赶时间。
  • 当我运行你的代码时,我得到了由[[[19, 58, 59, 60, 67, 103, 139, 148, 226]], [251]] 表示的 10 元素序列。这显然不是最理想的,因为我发现了一个包含 11 个元素的序列。在“输出”下,您报告了两个序列,每个序列有十个元素,如果它们是有效序列,这将是次优的,但它们不是;这些序列中的大多数值都不包含在任何子数组中(即arr.flatten &amp; [20, 132, 143, 148, 202, 209, 232, 265, 266, 269]).size #=&gt; 2(arr.flatten &amp; [18, 80, 93, 99, 131, 209, 232, 265, 266, 269]).size =&gt; 3
  • @CarySwoveland 第一组[20, 132, 143, 148, 202, 209, 232, 265, 266, 269]从第98组[18, 20, 139, 247, 259]开始。你能给我11个数字序列和它开始的集合吗?顺便说一句,您是否在没有任何修改的情况下运行了当前代码?次优是什么意思?
  • 对不起,我以为我在发表评论之前已经发布了我的解决方案。它准备好了,但还没有派出。我的回答中给出了各种解决方案。如果您认为这是一个优化问题——确实如此——问题是找到一个长度不被任何其他可行序列超过的“可行”序列(满足规则的序列)。这样的顺序是最优的;较短的可行序列是“次优的”。我没有修改就运行了你的代码。我没有意识到您在链接中指的是arr,但有更长的可行序列。
【解决方案2】:

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

[编辑] :算法现在在序列中选择下一个更大的数字时跳过阵列的所有可能的排列运行。现在保证算法返回最优解。

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]

【讨论】:

  • 这会产生 10 个元素的序列,[19, 41, 59, 60, 67, 101, 106, 148, 151, 256]。这不是最优的,因为我发现了 11 个元素的序列。
  • 感谢 Cary,算法已经过修改,现在可以找到最优解。
【解决方案3】:

接近

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

  • 阶段是子阵列;
  • 状态变量是序列的最大元素;
  • 要最大化的函数,在每个阶段i0 &lt;= i &lt; arr.size,对于每个n0 &lt;= n &lt;= largest(其中largest是所有子数组中的最大值:arr.flatten.max),是最大化取自arr[0],...arr[i] 的最长序列的长度,使得该序列的最大(最后)值为n

不熟悉“动态编程”?如果是这样,那不是问题,因为这里的优化技术简单直观。

我们将依次检查每个子数组arr[j], j=0..arr.size-1。对于每个这样的j 和每个n0 &lt;= n &lt;= largest (largest = arr.flatten.max),我们将数组longest[n] 定义为从子数组arr[0]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]

对于您的数组arrlink 你给:

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]

【讨论】:

  • 我明白了。您的解决方案实际上跳过了一组。我的没有。
  • 是的,问题指出,“每个嵌套数组都应该只提供一个元素或零个元素。”和“......可以跳过一些嵌套数组”。
  • 我明白了。我也尝试过,但到目前为止我仍然觉得它很复杂。你应该得到复选标记。 +1 :)
猜你喜欢
  • 2018-03-26
  • 2018-05-19
  • 2011-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多