炒冷饭,面试题--N对括号组合与打印的Python代码

这是一个面试题,虽然我没有遇到过,但在github上搜interview的时候发现了。想起自己曾经写过,但review的时候,发现写的太渣,于是重新写了一边。

基本思路:

    0. N对括号,抽象一下,我们处理的基本单元是一个括号对,即'{}'这样一个整体,而不是单个的'{'或'}'。

    1. 考虑 N = 0,1,2 直接对应 no brackets, '{}', ('{}{}', '{{}}') 这样简单的结果,因此编写的程序直接考虑 N >= 3的情况。

    2. 基于第0条,将一对括号抽象为一个节点,那么对于任意N(>=3)对括号,其所有的合法组合都可以用树和森林表示,例如,括号对-B和括号对-C在括号对-A内,那么B和C就是A的子节点,B和C互为兄弟节点。

    3. 虽然树和森林可以转化为二叉树,但实际效果,这样的转化会使问题复杂化。

    4. 如何表示一种树和森林,先序遍历树和森林,遍历时记录当前节点有多少个字节点,整体结果用一个list存储。例如对于 '{{{}{}}{{}{}}}' 可以描述为一个3层的完全二叉树,我们用list [2, 2, 0, 0, 2, 0, 0]来表示,并且实际上,最后一个节点肯定是没有子节点的,那么该list可以写为 [2, 2, 0, 0, 2, 0]。求出对于给定N,所有有效的list,即为所有有效的组合。

    5. 如何计算出/生成一个list,方便起见,基于第4条,我们从遍历顺序中的倒数第二个节点开始计算,依此计算到第一个节点,并且认为第二节点在list中对应的index=0,即第一个位置,第一个节点对应list中index=-1的位置。倒数第二个节点可能的子节点数为(0, 1),倒数第三个节点可能的子节点数为(0, 1, 2),依此类推,通项即range(index+2),实际中,如果倒数第二个节点取值为0或1,那么倒数第三个节点的对应可能取值为(0, 1, 2)和(0, 1),依此类推,某一节点可能取值的范围通项即为range(index+2-sum(list[:index]))。


以下是Python代码,python version : 2.7。

#!/usr/bin/env python

##### WARNING #####
# the main process steps in this file have low efficiency
# because we attempt to compute out every results in
# each situation.
 
import sys
from math import factorial as fac
from collections import deque
from Queue import LifoQueue
 
def get_input_num():
    if len(sys.argv) != 2:
        print 'invalid usage...'
        print 'use like this : ./this-prog number-to-calculate'
        sys.exit(1)
    ret = sys.argv[1]
    if not ret.isdigit():
        print 'invalid usage...'
        print 'the argument should be  type'
        sys.exit(1)
        return int(ret)

def check(num, N):
    chk = fac(N * 2)/(fac(N) * fac(N)) - fac(N * 2)/(fac(N + 1) * fac(N - 1))
    prt = [str(num), '==' if num == chk else '!=', str(chk)]
    print ' '.join(prt)
 
def gen(N):
    seeds = deque(([0],[1]))
    if N > 2:
    while 1:
        seed = seeds.popleft()
        index, used = len(seed), sum(seed)
        remain = index + 1 - used
        seeds.extend([seed + [i] for i in xrange(remain + 1)])
        if len(seeds[0]) == N - 1:
            break
    return seeds

def paint(seeds):
    def gen(content=''):
        return '{' + content + '}'
    for seed in seeds:
        lq = LifoQueue()
        lq.put(gen())
        for i in seed:
            if i != 0:
                new_cont = gen(''.join([lq.get() for j in xrange(i)]))
            else:
                new_cont = gen()
                lq.put(new_cont)
        print seed + [0], ':', ''.join(lq.queue)

if __name__=='__main__':
    N = get_input_num()
    if N == 0:
        print 'no brackets...'
        sys.exit(0)
    if N == 1:
        print '{}'
        sys.exit(0)
    res = gen(N)
    check(len(res), N)
    paint(res)     


你可能感兴趣的:(面试题,python学习)