我正在解决Ruby中的玩具问题:如何生成所有可能的10位数电话号码,其中每个连续数字与键盘上的最后一个数字相邻。我已经表示了数字之间的相邻关系,并且具有递归函数,但我的方法并没有遍历整个解空间。它只是找到第一个解决方案并返回。
这是我的代码:
adjacencies = { 1 => [2, 4],
2 => [1, 3, 5],
3 => [2, 6],
4 => [1, 5, 7],
5 => [2, 4, 6, 8],
6 => [3, 5, 9],
7 => [4, 8],
8 => [5, 7, 9, 0],
9 => [6, 8],
0 => [8]
}
def append_number(partial_phone_number, to_append, adjacencies)
phone_length = 10
partial_phone_number = partial_phone_number + to_append.to_s
if (partial_phone_number.length == phone_length)
return partial_phone_number
else
adjacencies[to_append].each do |a|
return append_number(partial_phone_number, a, adjacencies)
end
end
end
(0..9).each do |n|
puts append_number("", n, adjacencies)
end
这是运行时的输出:
0852121212
1212121212
2121212121
3212121212
4121212121
5212121212
6321212121
7412121212
8521212121
9632121212
答案 0 :(得分:2)
第一次输入adjacencies[to_append].each
时,您立即从方法中return
,因此循环永远不会被执行多次。
你需要
答案 1 :(得分:1)
以下是递归方法的修改。 FIRST_DIGIT
是n
个数字电话号码的可能第一个数字的数组,n
是方法recurse
的第一个参数。您希望确定recurse(10)
。
ADJ = { 1 => [2, 4],
2 => [1, 3, 5],
3 => [2, 6],
4 => [1, 5, 7],
5 => [2, 4, 6, 8],
6 => [3, 5, 9],
7 => [4, 8],
8 => [5, 7, 9, 0],
9 => [6, 8],
0 => [8]
}
FIRST_DIGIT = (1..9).to_a
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9]
def recurse(n, nxt=FIRST_DIGIT)
nxt.each_with_object([]) do |i,a|
is = i.to_s
if n==1
a << is
else
recurse(n-1, ADJ[i]).each { |s| a << is + s }
end
end
end
recurse 1
#=> ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
recurse 2
#=> ["12", "14", "21", "23", "25", "32", "36", "41", "45",
# "47", "52", "54", "56", "58", "63", "65", "69",
# "74", "78", "85", "87", "89", "80", "96", "98"]
recurse 3
#=> ["121", "123", "125", "141", "145", "147",
# "212", "214", "232", "236", "252", "254", "256", "258",
# "321", "323", "325", "363", "365", "369",
# "412", "414", "452", "454", "456", "458", "474", "478",
# "521", "523", "525", "541", "545", "547", "563", "565",
# "569", "585", "587", "589", "580",
# "632", "636", "652", "654", "656", "658", "696", "698",
# "741", "745", "747", "785", "787", "789", "780",
# "852", "854", "856", "858", "874", "878", "896", "898", "808",
# "963", "965", "969", "985", "987", "989", "980"]
recurse(10).size
#=> 117529
[编辑: OP询问了修改代码以避免循环的可能性。这并不困难。也可以使用相同的修改来强制执行其他规则(例如,没有666
),所有这些都将减少要考虑的组合的数量。我们可以通过向so_far
添加一个参数recurse
来实现这一点,该参数是到目前为止所选数字的一个数组(或者它可以是一个字符串):
def recurse(n, so_far=[], nxt=FIRST_DIGIT)
nxt.each_with_object([]) do |i,a|
is = i.to_s
if n==1
a << is
else
< construct array 'permitted' from ADJ[i] and other rules >
recurse(n-1, so_far+[i], permitted).each { |s| a << is + s }
end
end
end
请注意,使用默认值的两个参数不是问题,因为recurse
最初只使用第一个参数调用,然后将使用所有三个参数调用。
答案 2 :(得分:0)
return
迭代器中的each
语句在第一次迭代时退出递归调用。不要在那里使用return
。一种可能的解决方案是在到达递归基本情况时将结果附加到列表(通过参数传递)。