Ruby中的回溯与组合电子问题

Ruby中的回溯与组合电子问题,ruby,recursion,combinatorics,backtracking,Ruby,Recursion,Combinatorics,Backtracking,所以我一直在尝试解决这个问题,我有点坚持使用回溯实现它,我真的很想了解我在这里做错了什么。我怀疑我的问题与在方法中通过引用传递数组有关,但我似乎无法指出这一点。感谢您的帮助。这是在一次采访中被问到的,我正试图自己解决这个问题 问题是: 卡片有套牌和重复时间。给定一个卡片列表和输出大小,返回一个列表,其中包含 (所有相同的字母或所有不同的字母)& (所有相同的长度或所有不同的字母长度) 我的算法如下: 调用一个helper方法,该方法返回这样一个组合是否存在以及该组合是否存在 helper方法获

所以我一直在尝试解决这个问题,我有点坚持使用回溯实现它,我真的很想了解我在这里做错了什么。我怀疑我的问题与在方法中通过引用传递数组有关,但我似乎无法指出这一点。感谢您的帮助。这是在一次采访中被问到的,我正试图自己解决这个问题

问题是:

卡片有套牌和重复时间。给定一个卡片列表和输出大小,返回一个列表,其中包含


(所有相同的字母或所有不同的字母)& (所有相同的长度或所有不同的字母长度)

我的算法如下:

  • 调用一个helper方法,该方法返回这样一个组合是否存在以及该组合是否存在
  • helper方法获取输出中所需的卡片列表和卡片数量
  • 基本情况:如果计数为0,则返回true和空数组(表示我们没有更多的卡可供选择)
  • 迭代每一张卡片
  • 查找计数为1的卡的组合,并选择当前卡(递归)
  • 如果找到组合,请检查当前卡,确保可以将其添加到当前组合并返回
  • 如果您已经遍历了所有卡,但找不到组合,请使用空数组返回false
def唯一\u卡(卡,计数)
can,picked_cards=_unique_cards(卡片,计数)
放罐头?选卡:假
结束
def_唯一_卡(卡,计数)
如果计数=0,则返回[true,[]
卡片。每张卡片|
卡片长度=卡片长度
卡片类型=卡片[0]
剩余卡片=卡片-[卡片]
can,选定的\u卡=\u唯一的\u卡(剩余的\u卡,计数-1)
如果可以
可不可以添加=(已选卡.all?{c1{c1.length==card{u length}}已选卡.all{c1{c1[0]==card{u type})和(已选卡.all{c1{c1.length!=card{u length}已选卡.all{c1}c1[0]=card{u type})
如果可以添加
选定的卡
在第一个示例中,如果没有
.uniq(&:to\u set)
,我们将获得

find_em ['Y', 'Y', 'Z', 'ZZ', 'X', 'XX', 'Y'], 3
  #=> [["Y", "Y", "Y"], ["Y", "Z", "X"], ["Y", "Z", "X"], ["Z", "X", "Y"]]

请参阅和。

“所有相同的字母或所有不同的字母&所有相同的长度或所有不同的字母长度”对我来说有点模糊,您是否可以为输入和输出添加更多示例?乍一看,我发现一个错误,“puts can?picked_cards:false”始终返回零,如果要显示结果并返回值,请使用p而不是putsI,但不要理解puts vs p参数。我试着用p替换,但还是一样。我又添加了几个例子来说明这一点。基本上,我们希望返回n个卡片,其中的卡片(所有相同的套件或所有不同的套件)和(所有相同的长度或所有不同的长度)。“我怀疑我的问题与方法中通过引用传递的数组有关”-Ruby是通过值传递,而不是通过引用传递,所以这不可能是问题所在。@JörgWMittag:我认为这是定义对象的40字节的传递值。如果对象指向其他数据(数组的单元格、字符串中的字符等),则需要小心。d=[1,2];def f(a);a[0]=0;结束;f(d);d#=>[0,2]这个解决方案确实有效,这是一种非常Ruby的方式。对于较大的场景,我想这需要很长时间。空间的复杂性尤其巨大。我们将存储大小为n的所有可能组合。我在寻找更多的回溯式解决方案。更具体地说,我是在寻找我的方法中的问题。如果我不能很快好转,我会接受这个答案。谢谢你的回答!但我必须说,你提供的解决方案给我留下了深刻的印象。非常清楚这里发生了什么。有几点:1)对于大型阵列,所有方法都将非常耗时;2)
Array#composition
不带块返回一个枚举数,因此所需的内存量将取决于作为uniq(&:to_set)接收器的数组的大小
<代码>数组#组合是用
C
编写的,因此它比使用递归生成组合要快得多;4) 以牺牲内存为代价,您可以维护一组已经检查过的组合(保存为集合)。例如,如果您检查了
[“X”、“Y”、“Z”]
,您可以将
#
保存到该集合中,允许您跳过
[“Y”、“X”、“Z”]
,……例如,如果出现;5) 布丁的证据在于吃,所以让我们看看是否有更快的解决方案@卡里:如果“卡片”代表一个独特的/物理的项目,那么保留“重复的”组合是有意义的。还有,为什么要使用Array#select而不是Array#find?
  def unique_cards(cards, count)
    can, picked_cards = _unique_cards(cards, count)
    puts can ? picked_cards : false
  end

  def _unique_cards(cards, count)
    return [true, []] if count == 0
    cards.each do |card|
      card_length = card.length
      card_type = card[0]
      remaining_cards = cards - [card]
      can, selected_cards = _unique_cards(remaining_cards, count - 1)
      if can
        can_be_added = (selected_cards.all? { |c1| c1.length == card_length } || selected_cards.all? { |c1| c1[0] == card_type }) && (selected_cards.all? { |c1| c1.length != card_length   } || selected_cards.all? { |c1| c1[0] != card_type })
        if can_be_added
          selected_cards << card
          return [true, selected_cards]
        end
      end
    end
    return [false, []]
  end
require 'set'

def find_em(arr, n)
  arr.combination(n)
     .select do |a|
       [1, n].include?(a.map { |s| s[0] }.uniq.size) &&
       [1, n].include?(a.map(&:size).uniq.size)
      end.uniq(&:to_set)
end
find_em ['Y', 'Y', 'Z', 'ZZ', 'X', 'XX', 'Y'], 3
  #=> [["Y", "Y", "Y"], ["Y", "Z", "X"]]
find_em ['X', 'Y', 'YY', 'ZZ', 'ZZZ'], 3
  #=> [["X", "YY", "ZZZ"]]
find_em ['X', 'Y', 'YY', 'ZZ', 'ZZ'], 3
  #=> []
find_em ['Y', 'Y', 'Z', 'ZZ', 'X', 'XX', 'Y'], 3
  #=> [["Y", "Y", "Y"], ["Y", "Z", "X"], ["Y", "Z", "X"], ["Z", "X", "Y"]]