将牛客网上剑指offer的题刷了两遍了,感觉需要总结一下,有个系统的认识。
目录
一、二叉树简介
二叉树是一种常见的数据结构,它的每个节点最多只能有两个子节点。利用Python构建二叉树的代码如下:
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
二、二叉树的遍历
在二叉树中首先要掌握的基本操作就是树的遍历,很多关于二叉树的题目都可以在遍历的基础上进行修改。一般来说,二叉树有如下几种遍历方式:(以根节点的访问顺序来命名)
- 前序遍历:先访问根节点,再访问左子节点,最后访问右子节点。前序遍历的代码如下:
def preOrder(root):
if not root:
return []
res = []
res.append(root)
preOrder(root.left)
preOrder(root.right)
return res
- 中序遍历:先访问左子节点,再访问根节点,最后访问右子节点。中序遍历的代码如下:
def inOrder(root):
if not root:
return []
res = []
inOrder(root.left)
res.append(root)
inOrder(root.right)
return res
- 后序遍历:先访问左子节点,在访问右子节点,最后访问根节点。后序遍历的代码如下:
def postOrder(root):
if not root:
return []
res = []
postOrder(root.left)
postOrder(root.right)
res.append(root)
return res
三、二叉树遍历相关题目
1. 重建二叉树
题目描述:
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
解题思路:
由于前序遍历首先访问根节点,因此前序遍历的第一个数字就是根节点的值。然后根据根节点在中序遍历中的位置就可以确定左子树和右子树中的节点的值。如下图所示,在根节点的值1的前面的3个数字是左子树节点的值,位于1后面的数字都是右子树节点的值。
现在,我们已经分别找到了左、右子树的前序遍历和中序遍历序列,接下来我们就可以用相同的方法分别去构建左右子树。也就是说,可以用递归的方法来实现。
class Solution:
# 返回构造的TreeNode根节点
def reConstructBinaryTree(self, pre, tin):
# write code here
if pre==[]:
return
root = TreeNode(pre[0])
i = tin.index(pre[0])
root.left = self.reConstructBinaryTree(pre[1:i+1],tin[:i])
root.right = self.reConstructBinaryTree(pre[i+1:],tin[i+1:])
return root
2. 把二叉树打印成多行
题目描述:
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。如上图所示的二叉树,打印的结果为[[1],[2,3],[4,5,6],[7,8]]。
解题思路:
这道题实质上也是在考察树的遍历算法。在解这道题时,我们需要建立两个数组tmp和tmpRoot来分别记录当前层从左到右节点的值和下一层的节点。建立数组cur来放置当前层的节点。
class Solution:
def Print(self, pRoot):
# write code here
if not pRoot:
return []
cur = [pRoot] #记录当前层的节点
res = []
while cur!=[]:
tmp = [] #记录当前层节点的值
tmpRoot = [] #记录下一层的节点
for i in cur:
tmp.append(i.val)
if i.left:
tmpRoot.append(i.left)
if i.right:
tmpRoot.append(i.right)
res.append(tmp)
cur = tmpRoot
return res
3. 按之字形顺序打印二叉树
题目描述:
按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。如上图所示的二叉树,打印的结果为[[1],[3,2],[4,5,6],[8,7]]。
解题思路:
这道题的做法基本与上一道题一致,只是需要立一个flag:flag=0表示奇数行,无需改动;flag=1表示偶数行,需要对该行进行翻转。
class Solution:
def Print(self, pRoot):
# write code here
if not pRoot:
return []
cur = [pRoot] #记录当前层的节点
res = []
flag = 0
while cur!=[]:
tmp = [] #记录当前层节点的值
tmpRoot = [] #记录下一层的节点
for i in cur:
tmp.append(i.val)
if i.left:
tmpRoot.append(i.left)
if i.right:
tmpRoot.append(i.right)
if flag:
tmp = tmp[::-1]
flag = 1-flag
res.append(tmp)
cur = tmpRoot
return res
4. 二叉树的镜像
题目描述:
操作给定的二叉树,将其变换为源二叉树的镜像。
解题思路:
二叉树镜像的定义:
源二叉树 镜像二叉树
由上图可知,两个互为镜像的二叉树的根节点相同,左、右两个节点位置互换。因此,求一棵树的镜像的过程如下:先前序遍历这棵树的每个节点,如果遍历到的节点有子节点,就交换它的两个子节点。当交换完所有非叶子节点的左右节点之后,就得到了树的镜像。
class Solution:
# 返回镜像树的根节点
def Mirror(self, root):
# write code here
if not root:
return None
#交换左、右子节点的位置
tmp = root.left
root.left = root.right
root.right = tmp
#遍历所有节点
self.Mirror(root.left)
self.Mirror(root.right)
return root
参考文献:《剑指offer》