你能帮我做一次练习吗?文字是:我们有一个手机键盘。只有当数字中的每个下一个数字都是先前的邻居时,我们才能使用某个数字。例如,如果我们有数字8,我们可以使用5,7,9,0,或者如果我们有7,我们只能使用4和8.练习是,写一个函数,参数k> = 1返回我们可以使用的所有k位数。例如,k == 2的函数应返回26.我希望这是可以理解的。我完全不明白这项练习对我的要求。请注意,这不是家庭作业或类似的东西。谢谢你的回答。
答案 0 :(得分:2)
解决此任务的关键是使用字典,根据键盘上数字的分布将数字映射到可能的后继字符。这本词典可能像这样循环:
succ = {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 comb_recursive(current, k):
if len(current) >= k:
yield current
else:
next = succ[current[-1]] if current else [1,2,3,4,5,6,7,8,9,0]
for n in next:
for c in comb_recursive(current + [n], k):
yield c
或者使用迭代方法,即使用堆栈而不是递归。
def comb_stack(k):
stack = [[i] for i in range(10)]
while stack:
current = stack.pop()
if len(current) >= k:
yield current
else:
stack.extend([current + [n] for n in succ[current[-1]]])
另一个变体是首先生成所有组合,然后过滤那些有效的组合,但这虽然非常优雅且易于理解,但也有点浪费。
from itertools import product
def comb_filter(k):
return [comb
for comb in product(range(10), repeat=k)
if all(y in succ[x] for x, y in zip(comb, comb[1:]))]
事实上,IPython的%timeit
表明它的很多更慢:
In [13]: %timeit list(comb_recursive([], 5))
100 loops, best of 3: 2.25 ms per loop
In [14]: %timeit list(comb_stack(5))
100 loops, best of 3: 1.84 ms per loop
In [15]: %timeit comb_filter(5)
1 loops, best of 3: 453 ms per loop
在任何情况下,您现在都可以调用该函数并使用len
来获取有效组合的数量。
>>> combs = list(comb_recursive([], 2))
>>> combs
[[1, 2], [1, 4], [2, 1], [2, 3], [2, 5], [3, 2], [3, 6], [4, 1], [4, 5], [4, 7], [5, 2], [5, 4], [5, 6], [5, 8], [6, 3], [6, 5], [6, 9], [7, 4], [7, 8], [8, 5], [8, 7], [8, 9], [8, 0], [9, 6], [9, 8], [0, 8]]
>>> len(combs)
26
注意:如果您只需要 有效组合的数量,则可能会有更简单的解决方案。