我正在尝试生成所有可能的键盘序列(目前只有7位数字长度)。例如,如果移动键盘看起来像这样:
1 2 3
4 5 6
7 8 9
0
一些可能的序列可以是:
123698
147896个
125698个
789632
要求是数字的每个数字应该是前一个数字的邻居。
以下是我计划如何开始这个:
有关邻居的信息从键盘变为键盘,因此我们必须对其进行硬编码:
neighbors = {0: 8, 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: [7,5,9,0], 9: [6,8]}
我将遍历所有数字并将附加一个可能的邻居,直到达到所需的长度。
编辑:更新了邻居,不允许使用对角线 编辑2:数字可以重复使用
答案 0 :(得分:3)
试试这个。
neighbors = {0: [8],
1: [2,4],
2: [1,4,3],
3: [2,6],
4: [1,5,7],
5: [2,4,6,8],
6: [3,5,9],
7: [4,8],
8: [7,5,9,0],
9: [6,8]}
def get_sequences(n):
if not n:
return
stack = [(i,) for i in range(10)]
while stack:
cur = stack.pop()
if len(cur) == n:
yield cur
else:
stack.extend(cur + (d, ) for d in neighbors[cur[-1]])
print list(get_sequences(3))
这将产生所有可能的序列。你没有提到你是否想要那些有循环的东西,例如(0, 8, 9, 8)
所以我把它们留了下来。如果你不想要它们,那么只需使用
stack.extend(cur + (d, )
for d in neighbors[cur[-1]]
if d not in cur)
请注意,我为0
条目创建了一个包含一个元素而不是整数的列表。这是为了保持一致。能够索引到字典并且知道你将获得一个列表是非常好的。
另请注意,这不是递归的。递归函数在正确支持它们的语言中很好。在Python中,您几乎应该像我在这里演示的那样管理堆栈。它就像递归解决方案一样简单,并且避开函数调用开销(python不支持尾递归)和最大递归深度问题。
答案 1 :(得分:1)
neighbors = {0: [8], 1: [2,5,4], 2: [1,4,3], 3: [2,5,6], 4: [1,5,7], 5: [2,4,6,8], 6: [3,5,9], 7: [4,5,8], 8: [7,5,9,0], 9: [6,5,8]}
def gen_neighbor_permutations(n, current_prefix, available_digit_set, removed_digits=set(), unique_digits=False):
if n == 0:
print current_prefix
return
for d in available_digit_set:
if unique_digits:
gen_neighbor_permutations(n-1, current_prefix + str(d), set(neighbors[d]).difference(removed_digits), removed_digits.union(set([d])), unique_digits=True )
else:
gen_neighbor_permutations(n-1, current_prefix + str(d), set(neighbors[d]).difference(removed_digits) )
gen_neighbor_permutations(n=3, current_prefix='', available_digit_set=start_set)
我也忍不住注意到在你的例子中,没有任何数字被重复使用。如果你想要,那么你可以使用unique_digits = True
选项;这将禁止对已使用的数字进行递归。
+1多么有趣的谜题。我希望这适合你!
gen_neighbor_permutations(n=3, current_prefix='', available_digit_set=start_set, unique_digits = True)
答案 2 :(得分:1)
递归在这里并不是一个问题,因为序列相对较短,除了第一个之外,每个数字的选择都是相对较短的 - 因此似乎“仅”有4790种可能不允许对角线。这是作为迭代器编写的,以消除创建和返回其中产生的所有可能性的大容器的需要。
我想到,在数据结构中存储邻居邻接信息的数据驱动方法的额外好处(如OP建议的那样)是除了容易支持不同的键盘之外,它还可以控制是否允许对角线或不是微不足道的。
我简单地讨论了是否要将其列为列表而不是字典以便更快地查找,但是意识到这样做会使得更难以适应生成除数字之外的序列(并且可能不会使其显着更快) )。
adjacent = {1: [2,4], 2: [1,3,4], 3: [2,6],
4: [1,5,7], 5: [2,4,6,8], 6: [3,5,9],
7: [4,8], 8: [0,5,7,9], 9: [6,8],
0: [8]}
def adj_sequences(ndigits):
seq = [None]*ndigits # pre-allocate
def next_level(i):
for neighbor in adjacent[seq[i-1]]:
seq[i] = neighbor
if i == ndigits-1: # last digit?
yield seq
else:
for digits in next_level(i+1):
yield digits
for first_digit in range(10):
seq[0] = first_digit
for digits in next_level(1):
yield digits
cnt = 1
for digits in adj_sequences(7):
print '{:d}: {!r}'.format(cnt, ''.join(map(str,digits)))
cnt += 1
答案 3 :(得分:0)
这是一种经典的递归算法。一些伪代码来显示这个概念:
function(numbers) {
if (length(numbers)==7) {
print numbers;
return;
}
if (numbers[last]=='1') {
function(concat(numbers, '2'));
function(concat(numbers, '4'));
return;
}
if (numbers[last]==='2') {
function(concat(numbers, '1'));
function(concat(numbers, '3'));
function(concat(numbers, '5'));
return;
}
...keep going with a condition for each digit..
}
答案 4 :(得分:0)
neighbors = {0: [8], 1: [2,5,4], 2: [1,4,3], 3: [2,5,6], 4: [1,5,7], 5: [2,4,6,8], 6: [3,5,9], 7: [4,5,8], 8: [7,5,9,0], 9: [6,5,8]}
def keyNeighborsRec(x, length):
if length == 0:
print x
return
for i in neighbors[x%10]:
keyNeighborsRec(x*10+i,length-1)
def keyNeighbors(l):
for i in range(10):
keyNeighborsRec(i,length-1)
keyNeighbors(7)
没有邻居条件,它真的很容易......
def keypadSequences(length):
return map(lambda x: '0'*(length-len(repr(x)))+repr(x), range(10**length))
keypadSequences(7)
答案 5 :(得分:0)
states = [
[8],
[2, 4],
[1, 3, 5],
[2, 6],
[1, 5, 7],
[2, 4, 6, 8],
[3, 5, 9],
[4, 8],
[5, 7, 9, 0],
[6, 8]
]
def traverse(distance_left, last_state):
if not distance_left:
yield []
else:
distance_left -= 1
for s in states[last_state]:
for n in traverse(distance_left, s):
yield [s] + n
def produce_all_series():
return [t for i in range(10) for t in traverse(7, i)]
from pprint import pprint
pprint(produce_all_series())