算法竞赛入门经典第6章例题(2):二叉树部分+四分树

46 篇文章 0 订阅

66 这是一道有关二叉树的1题目,但是如果你真的对它用二叉树进行模拟就入坑了,不需要真正的实现二叉树,也无关小球的编号大小,我们只需要判断第i次小球在第d层的行为既可。假设向左为0向右为1,这个行为序列的规律是:000,100,010,110,001,101,011,111。即第k位每 2k1 变动一次,根据这个规律,我们可以直接求解最终的位置。

def get_track(i,D):
    ans,i,pos = '',i-1,1
    for d in range(0,D-1):
        k = i>>d
        if k%2:pos = pos*2+1
        else:pos*=2
    print('*****:',pos)
def proc():
    num = int(input())
    while num>0:
        line = input()
        line = line.split(' ')
        D,I = int(line[0]),int(line[1])
        get_track(I,D)
        num-=1
proc()

上面的思路相对麻烦一点,书上提供了一种更加简单的方法,这种方法有点递归的思想:

i: ,

if i%2==1那么它就是第(i+1)/2个向左的小球,否则就是第i/2个向右的小球。那么该层的行为就可以确定。同时,对于左/右子树,i = next(i),继续这个判断既可。相对于我自己的办法,这种思路逻辑更加清晰,非常巧妙的解决了问题!代码如下:
def get_track(i,D):
    ans,pos = '',1
    for d in range(0,D-1):
        if i%2:pos,i = pos*2,(i+1)>>1
        else:pos,i=2*pos+1,i>>1

67 这题标准解法本身不复杂,就是不停的读入然后创建一个二叉树,再bfs层序遍历,同时进行检测。

但是我这里要提供一个我自己的思路,利用输入的路径进行排序可以直接得到层序遍历的结果。比较的函数返回一个tuple:(len(path),path),len(path)越小说明depth越小,在depth相同的情况下应该看谁在左边,因为字符串中‘L’<‘R’,所以可以直接比较字符串…..最后同样是根据排序好的节点建立一棵树,但是可以发现错误的输入就提前结束。

def proc_input():
    line = input()
    while line!='':
        nodes = []
        line = line.split(' ')
        for node_expr in line:
            if node_expr=='()':continue
            node_expr = node_expr[1:len(node_expr)-1]
            node_expr = node_expr.split(',')
            node = (node_expr[0],node_expr[1])
            nodes.append(node)
        nodes.sort(key = lambda x: (len(x[1]),x[1]))
        if test(nodes):print([i[0] for i in nodes])
        else:print(-1)
        line = input()

def test(nodes):
    root = nodes[0] if nodes[0][1]=='' else None
    if root==None:print('no root');return False
    tree = [root,None,None]
    curr,parent = tree,root
    for node in nodes[1:]:
        curr = tree
        for way in node[1]:
            if curr==None:break
            parent = curr
            if way=='L':curr = curr[1]
            else:curr = curr[2]
        if curr!=None:return False#repeat
        if parent[0][1]==node[1][:-1]:
            if way=='L':parent[1] = [node,None,None]
            else:       parent[2] = [node,None,None]
        else:print('len:',parent[0],node);return False
    return True
proc_input()

,还可以使用数组来表达二叉树,代码如下:

注意,下面的代码只针对上面的题目。

cnt,root = 1,1
left,right,halv_val = [0,0],[0,0],[0,0]
def newtree():
    left[root],right[root],halv_val[root] = 0,0,False
def newnode():
    global cnt,u
    u,cnt = cnt+1,cnt+1
    left.append(0);right.append(0);halv_val.append(False)
    return u
def addnode(node):
    global cnt,root
    u,way = 1,node[1]
    for d in way:
        if d=='':halv_val[root] = node
        elif d=='L':
            if left[u]==0:left[u]=newnode()
            u = left[u]
        else:
            if right[u]==0:right[u]=newnode()
            u = right[u]
        if halv_val[u]==True:assert(1<0)
        halv_val.append(node)
newtree()
print(halv_val,left,right)

68 采用了数组来实现二叉树。其实在python里面直接构造树反而更加方便一点。另外一个就是从两中遍历序列构造出二叉树并且进行dfs。

def createtree(inorder,postorder):
    global left,right,halv_val,cnt,root
    left,right,halv_val,cnt,root = [0],[0],[0],0,0
    def maketree(inorder):
        root = postorder.pop()
        rootindex = newnode()
        rootpos = inorder.index(root)
        lt,rt = inorder[0:rootpos],inorder[rootpos+1:]
        halv_val[rootindex] = root
        if rt!=[]:u=maketree(rt);right[rootindex] = u
        else:right[rootindex] = 0
        if lt!=[]: u = maketree(lt);left[rootindex] = u
        else:left[rootindex] = 0
        return rootindex
    return maketree(inorder)


def search():
    m = (1<<100,1<<100);L=[]
    def dfs(rootindex=1):
        nonlocal m
        root = int(halv_val[rootindex])
        if left[rootindex]==0 and right[rootindex]==0:
            m = min(m,(sum(L)+root,root))
        if left[rootindex]!=0:L.append(root);dfs(left[rootindex]);L.pop()
        if right[rootindex]!=0:L.append(root);dfs(right[rootindex]);L.pop()
    dfs()
    print(m)

createtree(list('3214576'),list('3125674'))
search()
createtree([7,8,11,3,5,16,12,18],[8,3,11,7,16,18,12,5])
search()

69 平衡的天平,在SICP里面也有类似的题目,不过那个构造相对复杂,这个就很精简了。递归的判断左右子天平是不是平横且自己是不是平衡。处理输入的部分就懒得写了…

def create_mobile(preorder):
    wl,dl,wr,dr = preorder.pop()
    b1,b2 = True,True
    if wl==0:b1,wl = create_mobile(preorder)
    if wr==0:b2,wr = create_mobile(preorder)
    return (b1 and b2 and wl*dl==wr*dr),wl+wr
print(create_mobile([[0,2,0,4],[0,3,0,1],[1,1,1,1],[2,4,4,2],[1,6,3,2]][::-1]))

610 下落的叶子,和6-9非常的相似,我这里也略去对输入的处理了。

def compute(preorder):
    value = {}
    def fall_tree(preorder,horizon):
        root = preorder.pop()
        value[horizon] = root+value[horizon] if horizon in value else root
        if preorder[-1]!=-1:fall_tree(preorder,horizon-1)
        else:preorder.pop()
        if preorder[-1]!=-1:fall_tree(preorder,horizon+1)
        else:preorder.pop()
        return 
    fall_tree(preorder[::-1],0)
    print([value[k] for k in sorted(value.keys())])
compute([5,7,-1,6,-1,-1,3,-1,-1])
compute([8,2,9,-1,-1,6,5,-1,-1,12,-1,-1,3,7,-1,-1,-1])

611 这道题书上的办法最简洁,两次遍历既可,但是我的办法更高效。

(a) 首先同时遍历两颗树,如果有一个同层次的节点是黑色的,就不需要遍历另外一棵树的节点了。
(b) 注意,对于(a),如果另一个树的对应节点是中间节点,应该将该节点下的四个字节点删除。
(c) 其次如果两个都是中间节点递归的计算既可。如果两个都是白色也不需要计算了。
(d) 比较麻烦的是一个是中间节点,一个是白色节点。这时候使用另一个函数去单独遍历该中间节点,注意遍历前应该将该中间节点重新压会序列里面。这样方便写代码。
def proc(p1,p2):
    sum = 0
    def remov(p):
        for i in range(4):p.pop()
    def compute(order,num):
        nonlocal sum
        root = order.pop()
        if root=='f':sum+=num
        elif root == 'p':
            for i in range(4):compute(order,num>>2)
    def quadtrees(preoder1,preoder2,num):
        nonlocal sum
        root1,root2 = preoder1.pop(),preoder2.pop()
        if root1=='f' or root2=='f':
            sum+=num
            if root1=='p':remov(preoder1)
            if root2=='p':remov(preoder2)
        elif root1 == 'e' and root2=='e':return
        elif root1=='p' and root2=='p':
            for i in range(4):quadtrees(preoder1,preoder2,num>>2);
        elif root1=='p':preoder1.append('p');compute(preoder1,num)
        else:           preoder2.append('p');compute(preoder2,num)
    quadtrees(p1[::-1],p2[::-1],1024)
    print(sum)
proc(list('ppeeefpffeefe'),list('pefepeefe'))
proc(list('peeef'),list('peefe'))
proc(list('peeef'),list('peepefefe'))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值