提取非连续集

时间:2018-10-20 00:06:35

标签: ruby

我想获取所有非连续的集合(即其元素在原始集合中不能相邻的任何子集):

go([1,2,3,4,5]) => [1],[1,3,5],[1,3],[1,4],[1,5],[2],[2,4],[2,5],[3]

我和以下人很接近

def go(ns)
  return [[]] if ns == [] || ns == nil
  return [[ns[0]]] if ns.length < 3
  (0..ns.length-1).to_a.map do |i|
    dup = go(ns[i+2..-1])
    dup.map do |a|
      [ns[i]] + a
    end
  end
end

这给出了:

[[[1, [3, 5]], [1, [4]], [1, [5]]], [[2, 4]], [[3, 5]], [[4]], [[5]]]

接近正确的结果(未命中[1],我只是弄乱了数组的连接,无法弄清楚如何使其平坦化。

请注意,元素可以是任何数字,它们只是无序的唯一数字,例如

[35, 40, 100, 54, 13]

1 个答案:

答案 0 :(得分:1)

对于给定的n > 1,我计算了一个包含所有数组的数组,这些数组包含一个或多个[a, ... , b]形式的整数,其中a >= 1b <= n以及每个相邻对的元素i, jj > i+1。如果n = 1,则返回[[1]]

我已经使用递归做到了这一点。 recurse(m,n)计算所有此类数组的第一个元素为m

代码

def doit(n)
  (1..n).reduce([]) { |a,m| a + recurse(m,n) }
end

def recurse(m,n)
  return [[m]] if m >= n-1
  (m+2..n).reduce([[m]]) { |a,p| a + recurse(p,n).map { |b| [m]+b } }
end

示例

doit 6
  #=> [[1], [1, 3], [1, 3, 5], [1, 3, 6], [1, 4], [1, 4, 6], [1, 5], [1, 6],
  #    [2], [2, 4], [2, 4, 6], [2, 5], [2, 6],
  #    [3], [3, 5], [3, 6], [4], [4, 6], [5], [6]]

doit 8
  #=> [[1], [1, 3], [1, 3, 5], [1, 3, 5, 7], [1, 3, 5, 8], [1, 3, 6],
  #    [1, 3, 6, 8], [1, 3, 7], [1, 3, 8], [1, 4], [1, 4, 6], [1, 4, 6, 8],
  #    [1, 4, 7], [1, 4, 8], [1, 5], [1, 5, 7], [1, 5, 8], [1, 6],
  #    [1, 6, 8], [1, 7], [1, 8],
  #    [2], [2, 4], [2, 4, 6], [2, 4, 6, 8], [2, 4, 7], [2, 4, 8], [2, 5],
  #    [2, 5, 7], [2, 5, 8], [2, 6], [2, 6, 8], [2, 7], [2, 8],
  #    [3], [3, 5], [3, 5, 7], [3, 5, 8], [3, 6], [3, 6, 8], [3, 7], [3, 8],
  #    [4], [4, 6], [4, 6, 8], [4, 7], [4, 8],
  #    [5], [5, 7], [5, 8],
  #    [6], [6, 8],
  #    [7],
  #    [8]]

说明

我相信,对于我来说,解释递归的工作方式的最清晰方法(尤其是对于使用递归的经验有限的读者而言)是在将代码puts加入盐渍之后简单地执行代码。每当方法调用自身时,我都会缩进,而方法返回时,我都会缩进。

INDENT = 6
@pos = 0
def indent;  @pos += INDENT; @s = ' '*@pos; end
def outdent; @pos -= INDENT; @s = ' '*@pos; end

def doit(n)
  puts "doit: n=#{n}"
  (1..n).reduce([]) do |a,m|
    puts "a=#{a}"
    puts "calling recurse(#{m},#{n})"
    indent
    a + recurse(m,n)
  end
end

def recurse(m,n)
  puts "\n#{@s}entered recurse(#{m},#{n})"
  if m >= n-1
    puts "#{@s}returning #{[[m]]} as m >= n-1\n\n"
    outdent
    return [[m]]
  end
  puts "#{@s}begin reduce"
  a = (m+2..n).reduce([[m]]) do |a,p|
    puts "#{@s}  p=#{p}, a=#{a}"
    puts "#{@s}  calling recurse(#{p},#{n})"
    indent
    arr = recurse(p,n).map { |b| [m]+b }
    puts "#{@s}  back to recurse(#{m},#{n}) from recurse(#{p},#{n})"
    puts "#{@s}  array returned mapped to #{arr}"
    a + arr
  end
  puts "#{@s}return #{a} from recurse(#{m},#{n})\n\n"
  outdent
  a
end 

doit 6

doit: n=6
a=[]
calling recurse(1,6)

      entered recurse(1,6)
      begin reduce
        p=3, a=[[1]]
        calling recurse(3,6)

            entered recurse(3,6)
            begin reduce
              p=5, a=[[3]]
              calling recurse(5,6)

                  entered recurse(5,6)
                  returning [[5]] as m >= n-1

              back to recurse(3,6) from recurse(5,6)
              array returned mapped to [[3, 5]]
              p=6, a=[[3], [3, 5]]
              calling recurse(6,6)

                  entered recurse(6,6)
                  returning [[6]] as m >= n-1

              back to recurse(3,6) from recurse(6,6)
              array returned mapped to [[3, 6]]
            return [[3], [3, 5], [3, 6]] from recurse(3,6)

        back to recurse(1,6) from recurse(3,6)
        array returned mapped to [[1, 3], [1, 3, 5], [1, 3, 6]]
        p=4, a=[[1], [1, 3], [1, 3, 5], [1, 3, 6]]
        calling recurse(4,6)

            entered recurse(4,6)
            begin reduce
              p=6, a=[[4]]
              calling recurse(6,6)

                  entered recurse(6,6)
                  returning [[6]] as m >= n-1

              back to recurse(4,6) from recurse(6,6)
              array returned mapped to [[4, 6]]
            return [[4], [4, 6]] from recurse(4,6)

        back to recurse(1,6) from recurse(4,6)
        array returned mapped to [[1, 4], [1, 4, 6]]
        p=5, a=[[1], [1, 3], [1, 3, 5], [1, 3, 6], [1, 4], [1, 4, 6]]
        calling recurse(5,6)

            entered recurse(5,6)
            returning [[5]] as m >= n-1

        back to recurse(1,6) from recurse(5,6)
        array returned mapped to [[1, 5]]
        p=6, a=[[1], [1, 3], [1, 3, 5], [1, 3, 6], [1, 4], [1, 4, 6], [1, 5]]
        calling recurse(6,6)

            entered recurse(6,6)
            returning [[6]] as m >= n-1

        back to recurse(1,6) from recurse(6,6)
        array returned mapped to [[1, 6]]
      return [[1], [1, 3], [1, 3, 5], [1, 3, 6], [1, 4], [1, 4, 6], [1, 5],
        [1, 6]] from recurse(1,6)

a=[[1], [1, 3], [1, 3, 5], [1, 3, 6], [1, 4], [1, 4, 6], [1, 5], [1, 6]]
calling recurse(2,6)

      entered recurse(2,6)
      begin reduce
        p=4, a=[[2]]
        calling recurse(4,6)

            entered recurse(4,6)
            begin reduce
              p=6, a=[[4]]
              calling recurse(6,6)

                  entered recurse(6,6)
                  returning [[6]] as m >= n-1

              back to recurse(4,6) from recurse(6,6)
              array returned mapped to [[4, 6]]
            return [[4], [4, 6]] from recurse(4,6)

        back to recurse(2,6) from recurse(4,6)
        array returned mapped to [[2, 4], [2, 4, 6]]
        p=5, a=[[2], [2, 4], [2, 4, 6]]
        calling recurse(5,6)

            entered recurse(5,6)
            returning [[5]] as m >= n-1

        back to recurse(2,6) from recurse(5,6)
        array returned mapped to [[2, 5]]
        p=6, a=[[2], [2, 4], [2, 4, 6], [2, 5]]
        calling recurse(6,6)

            entered recurse(6,6)
            returning [[6]] as m >= n-1

        back to recurse(2,6) from recurse(6,6)
        array returned mapped to [[2, 6]]
      return [[2], [2, 4], [2, 4, 6], [2, 5], [2, 6]] from recurse(2,6)

a=[[1], [1, 3], [1, 3, 5], [1, 3, 6], [1, 4], [1, 4, 6], [1, 5], [1, 6],
   [2], [2, 4], [2, 4, 6], [2, 5], [2, 6]]
calling recurse(3,6)

      entered recurse(3,6)
      begin reduce
        p=5, a=[[3]]
        calling recurse(5,6)

            entered recurse(5,6)
            returning [[5]] as m >= n-1

        back to recurse(3,6) from recurse(5,6)
        array returned mapped to [[3, 5]]
        p=6, a=[[3], [3, 5]]
        calling recurse(6,6)

            entered recurse(6,6)
            returning [[6]] as m >= n-1

        back to recurse(3,6) from recurse(6,6)
        array returned mapped to [[3, 6]]
      return [[3], [3, 5], [3, 6]] from recurse(3,6)

a=[[1], [1, 3], [1, 3, 5], [1, 3, 6], [1, 4], [1, 4, 6], [1, 5], [1, 6], 
   [2], [2, 4], [2, 4, 6], [2, 5], [2, 6], [3], [3, 5], [3, 6]]
calling recurse(4,6)

      entered recurse(4,6)
      begin reduce
        p=6, a=[[4]]
        calling recurse(6,6)

            entered recurse(6,6)
            returning [[6]] as m >= n-1

        back to recurse(4,6) from recurse(6,6)
        array returned mapped to [[4, 6]]
      return [[4], [4, 6]] from recurse(4,6)

a=[[1], [1, 3], [1, 3, 5], [1, 3, 6], [1, 4], [1, 4, 6], [1, 5], [1, 6],
   [2], [2, 4], [2, 4, 6], [2, 5], [2, 6], [3], [3, 5], [3, 6], [4], [4, 6]]
calling recurse(5,6)

      entered recurse(5,6)
      returning [[5]] as m >= n-1

a=[[1], [1, 3], [1, 3, 5], [1, 3, 6], [1, 4], [1, 4, 6], [1, 5], [1, 6],
   [2], [2, 4], [2, 4, 6], [2, 5], [2, 6], [3], [3, 5], [3, 6], [4], [4, 6], [5]]
calling recurse(6,6)

      entered recurse(6,6)
      returning [[6]] as m >= n-1

#=> [[1], [1, 3], [1, 3, 5], [1, 3, 6], [1, 4], [1, 4, 6], [1, 5], [1, 6],
#    [2], [2, 4], [2, 4, 6], [2, 5], [2, 6], [3], [3, 5], [3, 6], [4], [4, 6],
#    [5], [6]]