用键盘进行python练习

时间:2015-07-01 09:30:28

标签: python-3.x

你能帮我做一次练习吗?文字是:我们有一个手机键盘。只有当数字中的每个下一个数字都是先前的邻居时,我们才能使用某个数字。例如,如果我们有数字8,我们可以使用5,7,9,0,或者如果我们有7,我们只能使用4和8.练习是,写一个函数,参数k> = 1返回我们可以使用的所有k位数。例如,k == 2的函数应返回26.我希望这是可以理解的。我完全不明白这项练习对我的要求。请注意,这不是家庭作业或类似的东西。谢谢你的回答。

1 个答案:

答案 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

注意:如果您只需要 有效组合的数量,则可能会有更简单的解决方案。