生成所有可能的小键盘/小键盘序列

时间:2010-11-22 21:20:56

标签: python algorithm numbers

我正在尝试生成所有可能的键盘序列(目前只有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:数字可以重复使用

6 个答案:

答案 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())
相关问题