算法竞赛入门经典第6章例题(2):二叉树部分+四分树
2016-07-21 17:35
441 查看
6−6这是一道有关二叉树的1题目,但是如果你真的对它用二叉树进行模拟就入坑了,不需要真正的实现二叉树,也无关小球的编号大小,我们只需要判断第i次小球在第d层的行为既可。假设向左为0向右为1,这个行为序列的规律是:000,100,010,110,001,101,011,111。即第k位每2k−1变动一次,根据这个规律,我们可以直接求解最终的位置。
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
例题6−7这题标准解法本身不复杂,就是不停的读入然后创建一个二叉树,再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)
6−8采用了数组来实现二叉树。其实在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()
6−9平衡的天平,在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]))
6−10下落的叶子,和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])
6−11这道题书上的办法最简洁,两次遍历既可,但是我的办法更高效。
(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'))
相关文章推荐
- T-SQL常用数据库操作语句
- 【LeetCode】Add Two Numbers
- 虚拟机脚本
- Windows Server 2012 虚拟化实战:网络(二)
- 小谈 accpet_mutex_delay 参数
- The Text Splitting(字符串问题)
- LeetCode 171. Excel Sheet Column Number
- ubuntu学习 之 如何安装软件
- 《深度探索C++对象模型》2
- 源码阅读系列:为什么要阅读源码?
- Linux 下系统调用的三种方法
- js四舍五入
- html5自动定位
- get请求和post请求乱码分析
- bzoj 2734(状压DP+神题)
- [置顶] 堆栈
- linux上sed的详解
- 开发人员谷歌浏览器插件?
- Android自定义控件:动画类(4)-----自定义补间动画
- Paypal升级SSL,java