文章目录
LeetCode144二叉树的前序遍历
LeetCode94二叉树中序遍历
LeetCode145二叉树后序遍历
先序遍历:
即先访问节点(Node)本身,然后访问左(left subtree)、右子树(right subtree)
中序遍历:
即先访问左子树、然后再访问节点,最后访问节点。
后序遍历:
先访问左子树、在访问右子树,最后访问节点。
递归
class Node:
def __init__(self, value=None, left=None, right=None):
self.value = value
self.left = left # 左子树
self.right = right # 右子树
# -*- coding: utf-8 -*-
class Node:
def __init__(self,value=None,left=None, right=None):
self.value = value
self.left = left
self.right = right
def preTraverse(root):
# 前序遍历
if root == None:
return
print(root.value, end=' ')
preTraverse(root.left)
preTraverse(root.right)
def midTraverse(root):
# 中序遍历
if root == None:
return
midTraverse(root.left)
print(root.value, end=' ')
midTraverse(root.right)
def afterTraverse(root):
# 后序遍历
if root == None:
return
afterTraverse(root.left)
afterTraverse(root.right)
print(root.value, end=' ')
# 测试:
if __name__ == '__main__':
root = Node()
root = Node('D', Node('B', Node('A'), Node('C')), Node('E', right=Node('G', Node('F'))))
print('前序遍历:')
preTraverse(root)
print('\n中序遍历:')
midTraverse(root)
print('\n后序遍历:')
afterTraverse(root)
栈方法
# # -*- coding: utf-8 -*-
class Node:
def __init__(self, value=None, left=None, right=None):
self.value = value
self.left = left
self.right = right
def preTraverse(self):
"""
使用栈结构实现先序遍历的思路:先将该二叉树整体推入到栈中,
根据栈后进先出的特性,先将栈取出:打印输出该二叉树的值,
因此需要先将二叉树的右节点推入栈结构中(如果存在的话)
然后再将二叉树的左节点推入栈中(如果存在的话)
下一次从栈中取的话就能达到先去左节点,后取右节点的效果。
"""
if self.value == None:
return
stack = [self]
while stack:
current = stack.pop()
print(current.value, end=' ')
if current.right:
stack.append(current.right)
if current.left:
stack.append(current.left)
def midTraverse(self):
"""
中序遍历需要执行打印顺序为:左子树、节点、右子树
需要先找到该二叉树的的最小左子树,然后从这颗左子树开始遍历节点和右子树
"""
if self.value == None:
return
stack = []
current = self
while len(stack) != 0 or current:
if current: # 不断递进,直到找到当前树的最小左子树
stack.append(current)
current = current.left
else: # 当前的栈中末尾的树已经是最小树时
temp = stack.pop()
print(temp.value, end=' ') # 打印出了当前树的节点后,开始对右子树动刀子
current = temp.right
def afterTraverse(self):
if self.value == None:
return
stack1 = [self]
stack2 = []
#
while stack1: # 使用了两个栈进行存储,因此从两个栈就构成了一个队列,先进先出
current = stack1.pop()
stack2.append(current)
if current.left:
stack1.append(current.left)
if current.right:
stack1.append(current.right)
# 直接遍历stack2输出即可:
while stack2:
print(stack2.pop().value, end=' ')
# 测试:
if __name__ == '__main__':
root = Node('D', Node('B', Node('A'), Node('C')), Node('E', right=Node('G', Node('F'))))
print('前序遍历:')
root.preTraverse()
print('\n中序遍历:')
root.midTraverse()
print('\n后序遍历:')
root.afterTraverse()
二叉树层次遍历(BFS,DFS)
# 先造出来一棵简单的二叉树结构供使用
class Tree:
def __init__(self, list_of_three):
# list_of_three [1,2,3] 根左右
# print("依次输入树的根、左节点、右节点")
# .node其实是当前节点的值
# 面向对象思想还是挺有用的
if list_of_three[0] != 0:
self.node = list_of_three[0]
else:
self.node = "none"
if list_of_three[1] != 0:
self.left = list_of_three[1]
else:
self.left = "none"
if list_of_three[2] != 0:
self.right = list_of_three[2]
else:
self.right = "none"
# 进行广度优先遍历BFS
def BFS(root_node):
# pop(0)和append()是队列
q = []
q.append(root_node)
while len(q) != 0:
temp = q.pop(0)
print(temp.node)
if temp.left != "none":
q.append(temp.left)
if temp.right != "none":
q.append(temp.right)
# 使用递归方式实现DFS
def DFS_recursion(root_node):
print(root_node.node)
if root_node == "none":
return
if root_node.left != "none":
DFS_recursion(root_node.left)
if root_node.right != "none":
DFS_recursion(root_node.right)
# 使用栈来实现DFS
def DFS_stack(root_node):
# pop()和append()是栈,pop()就差个0与队列相比
s = []
if root_node == "none":
return
s.append(root_node)
while len(s) != 0:
temp = s.pop()
print(temp.node)
if temp.right != "none":
s.append(temp.right)
if temp.left != "none":
s.append(temp.left)
def main():
# 自定义搭建了一棵二叉树
node = "root"
n = [i for i in range(12)]
for i in range(12):
n[i] = Tree([i, 0, 0])
n[5] = Tree([5, n[10], n[11]])
n[4] = Tree([4, n[8], n[9]])
n[3] = Tree([3, n[6], n[7]])
n[2] = Tree([2, n[4], n[5]])
n[1] = Tree([1, n[2], n[3]])
# 变量的覆盖作用,导致之前的未被更新,解释性语言,所以赋值需要从后往前
print("--------------------------------------------------------------")
print("基于递归的深度优先遍历:")
DFS_recursion(n[1])
print("--------------------------------------------------------------")
print("基于栈的深度优先遍历:")
DFS_stack(n[1])
print("--------------------------------------------------------------")
print("广度优先遍历:")
BFS(n[1])
print("--------------------------------------------------------------")
if __name__ == "__main__":
main()
判断两颗树是否相同
def isSample(p,q):
if p == None and q == None:
return True
elif p and q:
return p.val == q.val and isSample(p.left, q.left) and isSample(p.right, q.right)
else:
return False
LeetCode98判断是否为合法的二分搜索树BST
def isValidBST(self, root, floor=float('-inf'), ceiling=float('inf')):
if not root:
return True
if root.val < floor or root.val > ceiling:
return False
return self.isValidBST(root.left, floor, root.val) and self.isValidBST(root.right, root.val, ceiling)
LeetCode236. 二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
示例 1:
输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3 。
示例 2:
输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出:5
解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。
示例 3:
输入:root = [1,2], p = 1, q = 2
输出:1
解题思路:
祖先的定义: 若节点 p 在节点 root 的左(右)子树中,或 p=root ,则称root 是 p的祖先。
最近公共祖先的定义: 设节点 root 为节点 p,q 的某公共祖先,若其左子节点 root.left和右子节点 root.right 都不是p,q 的公共祖先,则称root 是 “最近的公共祖先” 。
根据以上定义,若root 是 p,q 的 最近公共祖先 ,则只可能为以下情况之一:
p 和 q 在root 的子树中,且分列 root 的 异侧(即分别在左、右子树中);
p=root ,且 q 在root 的左或右子树中;
q=root ,且 p 在root 的左或右子树中;
考虑通过递归对二叉树进行先序遍历,当遇到节点 ppp 或 qqq 时返回。从底至顶回溯,当节点 p,qp, qp,q 在节点 rootrootroot 的异侧时,节点 rootrootroot 即为最近公共祖先,则向上返回 rootrootroot 。
递归解析:
终止条件:
当越过叶节点,则直接返回 null ;
当 root 等于p,q ,则直接返回root ;
递推工作:
开启递归左子节点,返回值记为left ;
开启递归右子节点,返回值记为 right ;
返回值: 根据 left 和 right ,可展开为四种情况;
当 left 和right 同时为空 :说明root 的左 / 右子树中都不包含p,q ,返回 null ;
当 left 和 right 同时不为空 :说明 p,q 分列在root 的 异侧 (分别在 左 / 右子树),因此root 为最近公共祖先,返回root ;
当left 为空 ,right 不为空 :p,q 都不在root 的左子树中,直接返回 right 。具体可分为两种情况:
p,q 其中一个在 root 的 右子树 中,此时 right 指向 p(假设为 p );
p,q 两节点都在 root 的 右子树 中,此时的 right 指向 最近公共祖先节点 ;
当left 不为空 ,right 为空 :与情况 3. 同理;
class Solution:
def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode:
if not root or root == p or root == q: return root
left = self.lowestCommonAncestor(root.left, p, q)
right = self.lowestCommonAncestor(root.right, p, q)
if not left and not right: return # 1.
if not left: return right # 3.
if not right: return left # 4.
return root # 2. if left and right:
LeetCode111. 二叉树的最小深度
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明:叶子节点是指没有子节点的节点。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:2
示例 2:
输入:root = [2,null,3,null,4,null,5,null,6]
输出:5
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def minDepth(self, root: TreeNode) -> int:
# 二叉树为空,最小高度为 0
if root == None:
return 0
# 只有根节点,最小高度为 1
if root.left == None and root.right == None:
return 1
# 左子树最小值和右子树最小值
leftMindepth = self.minDepth(root.left)
rightMindepth = self.minDepth(root.right)
# 如果节点的左子树不为空,右子树为空
if root.left != None and root.right == None:
return leftMindepth + 1
# 如果节点的右子树不为空,左子树为空
if root.left == None and root.right != None:
return rightMindepth + 1
# 左右子树都不为空
return min(leftMindepth, rightMindepth) + 1
LeetCode104. 二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回它的最大深度 3 。
# python3 递归
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
if not root:return 0
return max(self.maxDepth(root.left),self.maxDepth(root.right)) + 1
DFS
class Solution(object):
def maxDepth(self, root):
if not root:
return 0
paths= []
count = 1
stack = [(root,str(root.val),count)]
res = 0
while stack:
node,path,cou = stack.pop()
if not node.left and not node.right:
res = max(cou,res)
print(cou,path)
if node.left:
stack.append((node.left,path + '->' + str(node.left.val),cou + 1))
if node.right:
stack.append((node.right,path + '->' + str(node.right.val),cou + 1))
return res
BFS
class Solution(object):
def maxDepth(self, root):
if not root:
return 0
queue = [root]
height = 0
while queue:
currentSize = len(queue)
for i in range(currentSize):
node = queue.pop(0)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
height += 1
return height
LeetCode98. 验证二叉搜索树
给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
节点的左子树只包含 小于 当前节点的数。
节点的右子树只包含 大于 当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
示例 1:
输入:root = [2,1,3]
输出:true
示例 2:
输入:root = [5,1,4,null,null,3,6]
输出:false
解释:根节点的值是 5 ,但是右子节点的值是 4 。
class Solution:
def isValidBST(self, root):
def dfs(root,left,right):
if not root:
return True
elif left < root.val <right:
return dfs(root.left,left,root.val) and dfs(root.right,root.val,right)
else:
return False
return dfs(root,float('-inf'),float('inf'))
LeetCode226. 翻转二叉树
给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
示例 1:
输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]
示例 2:
输入:root = [2,1,3]
输出:[2,3,1]
示例 3:
输入:root = []
输出:[]
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
def traverse(root):
if root is None:
return None
root.left, root.right = root.right, root.left
self.invertTree(root.left)
self.invertTree(root.right)
traverse(root)
return root
LeetCode230. 二叉搜索树中第K小的元素
给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 1 开始计数)。
示例 1:
输入:root = [3,1,4,null,2], k = 1
输出:1
示例 2:
输入:root = [5,3,6,2,4,null,null,1], k = 3
输出:3
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def __init__(self):
self.rank = 0
self.res = 0
def kthSmallest(self, root, k):
"""
:type root: TreeNode
:type k: int
:rtype: int
"""
self.traverse(root,k)
return self.res
def traverse(self, root, k):
if not root: return;
self.traverse(root.left, k)
self.rank += 1
# 找出第k小的元素
if self.rank == k:
self.res = root.val
self.traverse(root.right, k)