花花酱blog:
Depth First Traversals:
(a) Inorder (Left, Root, Right) 中序:左中右
(b) Preorder (Root, Left, Right) 前序:中左右
(c) Postorder (Left, Right, Root) 后序:左右中
Breadth-First or Level Order Traversal 层序遍历BFS
94.Binary Tree Inorder Traversal
recursive way:
首先python的代码, function前面要加def,在call function的时候要加self.
在function里面没有标点符号。在function的parameter里面写上self
在recursive里面,我们用一个Helper function来循环
def inorderTraversal(self, root):
res = []
self.helper(root, res)
return res
def helper(self, root, res):
if root:
self.helper(root.left, res)
res.append(root.val)
self.helper(root.right, res)
If binary: O(log n)
If skewed: O(n)
iteratively:
def inorderTraversal(self, root):
res = []
stack = []
current = root
while True:
while current:
stack.append(current)
current = current.left
if not stack:
return res
current = stack.pop()
res.append(current.val)
current = current.right
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
stack = []
res = []
if not root:
return None
while root or stack:
while root:
stack.append(root)
root = root.left
root = stack.pop()
res.append(root.val)
root = root.right
return res
iterative的从root开始,先把root 放进stack,让current指到current.left,
然后把所有的current.left都放到stack里。一直到没有left.
查到3,没有left了,把3 pop出去,让res接收3
然后查3的right, 3 没有right,所以current = 下一个pop的,等于2
把2放进res里。然后查2的right->4.
4被放入stack,然后查4的左边,然后Pop4,再查4的右边,没有,则pop 1。
二叉树后序遍历两遍图解
226 翻转二叉树
def invertTree(self, root: TreeNode) -> TreeNode:
self.traverse(root)
//return root 就可以
return root
//过一遍每一个node
def traverse(self, root):
//这是base case
if not root:
return None
//让两个node相交换
//无所谓是前中后(不是有了子节点才能算出来的,到了这个点就交换两个下面的node也可以)
//用前置
root.left, root.right = root.right, root.left
self.traverse(root.left)
self.traverse(root.right)
用dynamic programing的想法做:
先是把大的problem分成小的problem
在任意一个点上,让左子树的左右翻转,让右子树的左右翻转,然后再翻转左子树和右子树
左子树翻转完之后必须要等于一个值(应该是左子树的root)
右子树翻转完之后必须要等于一个值(应该是右子树的root)
然后交换两个值就可以实现左右子树的翻转
def invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return None
left = self.invertTree(root.left)
right = self.invertTree(root.right)
root.right = left
root.left = right
return root
116. 填充每个节点的下一个右侧节点指针
因为原本没有point to any thing 就是point to NULL,所以我们不需要一开始把所有node point to null
def connect(self, root):
"""
:type root: Node
:rtype: Node
"""
if not root:
return None
node1 = root.left
node2 = root.right
self.traverse(node1, node2)
return root
def traverse(self, node1, node2):
if not node1 or not node2:
return None
/**** 前序位置 ****/
// 将传入的两个节点穿起来
node1.next = node2
// 连接相同父节点的两个子节点
self.traverse(node1.left, node1.right)
self.traverse(node2.left, node2.right)
// 连接跨越父节点的两个子节点
self.traverse(node1.right, node2.left)
114. 二叉树展开为链表
def flatten(self, root):
"""
:type root: TreeNode
:rtype: None Do not return anything, modify root in-place instead.
"""
#base case
if not root:
return None
#左子树展平
self.flatten(root.left)
#右子树展平
self.flatten(root.right)
if root.left:
#p是指向左子树root的指针
p = root.left
#当p有右节点时,一直向右
while p.right:
p = p.right
#把右子树接到左子树最右边的节点上
p.right = root.right
#左子树为空,原先的左子树赋值成为右子树
temp = root.left
root.left = None
root.right = temp
return root
递归的终极思想是:相信函数定义,跳出函数本身
二叉树解题的思维模式分两类:
1、是否可以通过遍历一遍二叉树得到答案?如果可以,用一个 traverse 函数配合外部变量来实现,这叫「遍历」的思维模式。
2、是否可以定义一个递归函数,通过子问题(子树)的答案推导出原问题的答案?如果可以,写出这个递归函数的定义,并充分利用这个函数的返回值,这叫「分解问题」的思维模式。
无论使用哪种思维模式,你都需要思考:
如果单独抽出一个二叉树节点,它需要做什么事情?需要在什么时候(前/中/后序位置)做?其他的节点不用你操心,递归函数会帮你在所有节点上执行相同的操作。
105. Construct Binary Tree from Preorder and Inorder Traversal
def buildTree(self, preorder, inorder):
return self.building(preorder,0, len(preorder)-1,inorder,0,len(preorder)-1)
def building(self,preorder,prestart, preend,inorder,instart,inend):
//base case
if (prestart > preend):
return None
target = preorder[prestart]
//找到inorder 里的root
for i in range(len(inorder)):
if inorder[i] == target:
index = i
# 先构造当前的根节点
root = TreeNode(target)
root.left = self.building(preorder,prestart+1,
prestart + index-instart, inorder,instart,index-1)
root.right = self.building(preorder,
prestart+index-instart+1, preend, inorder,index+1,inend)
return root
106. 从中序与后序遍历序列构造二叉树
def buildTree(self, inorder, postorder):
"""
:type inorder: List[int]
:type postorder: List[int]
:rtype: TreeNode
"""
#为了找到Index,构建helper function和left and right pointers
#左闭右闭
def dfs(inorder,left,right,postorder,start,end):
#base case
if left > right:
return None
#在后序中找到root,最后一个就是root
target = postorder[end]
#在中序中找root的index
for i in range(len(inorder)):
#如果值和root的值相等
if inorder[i] == target:
index = i
root = TreeNode(target)
#他的size不用加1
leftSize = index-left
root.left = dfs(inorder,left,index-1,postorder,start, start+leftSize-1)
root.right = dfs(inorder,index+1,right,postorder,start+leftSize,end-1)
return root
n=len(inorder)-1
return dfs(inorder,0,n,postorder,0,n)
时间复杂度:O(N^2) 因为每次递归都在当前长度上减少了一个根节点,所以需要N次,每次索引中序遍历数组为O(N),所以为平方级别复杂度
100. 相同的树(分治法)
def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
###递归输出条件,有一个空另外一个非空则False
if p is None and q is not None:
return False
###递归输出条件,有一个空另外一个非空则False
if p is not None and q is None:
return False
###递归输出条件,均为空则True
if p is None and q is None:
return True
#判断条件,值是否相等
if p.val != q.val:
return False
#递归为左树与右树是否相等
return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)
在Python里面,用elif,True和False首字母大写
分治法如果不能得到最终结果,循环的地方加return试一试
这题不能用简单的遍历,因为把null去掉了无法看出左边的树是否等于右边
102. Binary Tree Level Order Traversal
层序遍历的时候一定要使用BFS模版
BFS使用的时候通常与queue一起
首先要queue = collections.deque()
BFS模板
BFS的模版(如果不需