python-算法-二叉树相关问题的代码实现
原文章 https://zhuanlan.zhihu.com/p/44684273
二叉树的数据结构:
class TreeNode:
def __init__(self, val=0):
self.val = val
self.left = None
self.right = None
1.求二叉树的最大深度
def maxDeath(node): if not node: return 0 left = maxDeath(node.left) right = maxDeath(node.right) return max(left, right) + 1
2.求二叉树的最小深度
原文:
def getMin(root):
if not root:
return float('inf')
if not root.left and not root.right:
return 1
return min(getMin(root.left), getMin(root.right)) + 1
def getMinDepth(root):
if not root:
return 0
return getMin(root)
修改:
1 def minDepth( root): 2 if not root: 3 return float('inf') 4 if not root.left and not root.right: 5 return 1 6 left = self.minDepth(root.left) 7 right = self.minDepth(root.right) 8 return min(left, right) + 1
3.求二叉树中节点的个数
def numOfTreeNode(root):
if not root:
return 0
left = numOfTreeNode(root.left)
right = numOfTreeNode(root.right)
return left + right + 1
4.求二叉树中叶子节点的个数
def numsOfNoChildNode(root):
if not root:
return 0
if not root.left and not root.right:
return 1
return numsOfNoChildNode(root.left)+numsOfNoChildNode(root.right)
5.求二叉树中第K层节点的个数
def numsOfkLevelTreeNode(root, k):
if (not root) or k < 1:
return 0
if k == 1:
return 1
numsLeft = numsOfkLevelTreeNode(root.left, k-1)
numsRight = numsOfkLevelTreeNode(root.right, k-1)
return numsLeft + numsRight
6.判断二叉树是否是平衡二叉树
def maxDeath2(node):
if not node:
return 0
left = maxDeath2(node.left)
right = maxDeath2(node.right)
if left == -1 or right == -1 or abs(left-right)>1: # 子树不平衡
return -1
return max(left, right) + 1
def isBalanced(node):
return maxDeath2(node) != -1
7.判断二叉树是否是完全二叉树
def isCompleteTreeNode(root):
if not root:
return False
queue = [root]
result = True
hasNoChild = False
while queue: # 层次遍历
current = queue.pop(0)
if hasNoChild:
if current.left or current.right:
result = False
break
else:
if current.left and current.right:
queue.append(current.left)
queue.append(current.right)
# 当遇到只有左子树的分支时,看左子树是不是有孩子,如果有,返回False
elif current.left and not current.right:
queue.append(current.left)
hasNoChild = True
# 如果没有左子树,却有右子树,返回False
elif not current.left and current.right:
result = False
break
# 如果左右子树都没有,那就看下一个节点是否有左右子树,有,返回False
else:
hasNoChild = True
return result
8.判断两个二叉树是否完全相同
def isSameTreeNode(t1, t2):
if not t1 and not t2:
return True
elif not t1 or not t2:
return False
if t1.val != t2.val:
return False
left = isSameTreeNode(t1.left, t2.left)
right = isSameTreeNode(t1.right, t2.right)
return left and right
9.两个二叉树是否互为镜像
def isMirror(t1, t2):
if not t1 and not t2:
return True
if not t1 or not t2:
return False
if t1.val != t2.val:
return False
return isMirror(t1.left, t2.right) and isMirror(t1.right, t2.left)
10.翻转二叉树or镜像二叉树
def mirrorTreeNode(root):
if not root:
return None
left = mirrorTreeNode(root.left)
right = mirrorTreeNode(root.right)
root.left = right
root.right = left
return root
11.求两个二叉树的最低公共祖先节点
# 查找节点node是否在当前二叉树中
def findNode(root, node):
if not root or not node:
return False
if root == node:
return True
found = findNode(root.left, node)
if not found:
found = findNode(root.right, node)
return found
def getLastCommonParent(root, t1, t2):
if findNode(root.left, t1):
if findNode(root.right, t2):
return root
else:
return getLastCommonParent(root.left, t1, t2)
else:
if findNode(root.left, t2):
return root
else:
return getLastCommonParent(root.right, t1, t2)
12.二叉树的前序遍历
# 迭代解法
from collections import deque
def preOrder(root):
li = list()
if not root:
return li
stack = deque(root)
while stack:
node = stack.pop()
li.append(node.val)
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
return li
# 递归解法
def preOrder2(root, result):
if not root:
return None
result.append(root.val)
preOrder2(root.left, result)
preOrder2(root.right, result)
def preOrderReverse(root):
result = []
preOrder2(root, result)
return result
13.二叉树的中序遍历
def inOrder(root):
li = list()
current = root
stack = list()
while current or stack:
while current:
stack.append(current)
current = current.left
current = stack[-1]
stack.pop()
li.append(current.val)
current = current.right
return li
14.二叉树的后序遍历
def postOrder():
li = []
if not root:
return li
li.append(postOrder(root.left))
li.append(postOrder(root.right))
li.append(root.val)
return li
15.前序遍历和中序遍历构造二叉树,注意:已知前序和后序无法确定二叉树
def findPosition(arr, start, end, key):
for i in range(start, end+1):
if arr[i] == key:
return i
return -1
def myBuildTree(inorder, instart, inend, preorder, prestart, preend):
if instart > inend:
return None
# 前序遍历的第一个节点就是根节点
root = TreeNode(preorder[prestart])
# 找到前序遍历的起始节点在中序遍历中的位置,将中序遍历分成两部分
position = findPosition(inorder, instart, inend, preorder[prestart])
# 第一部分是根节点之前的遍历,是根节点的左子树
root.left = myBuildTree(inorder, instart, position-1, preorder, prestart+1, prestart+position-instart)
# 第二部分是根节点之后的遍历,是根节点的右子树
root.right = myBuildTree(inorder, position+1, inend, preorder, position-inend+preend+1, preend)
return root
def bulidTreeNode(preorder, inorder):
if len(preorder) != len(inorder):
return None
return myBuildTree(inorder, 0, len(inorder)-1, preorder, 0, len(preorder)-1)
16.在二叉树中插入节点
def insertNode(root, node):
if root == node:
return node
tmp = root
last = None
# 找到插入节点的位置
while tmp:
last = tmp
if tmp.val > node.val:
tmp = tmp.left
else:
tmp = tmp.right
if last:
if last.val>node.val:
last.left = node
else:
last.right = node
return root
17.输入一个二叉树和一个整数,打印出二叉树中节点值的和等于输入整数所有的路径
def findPath(r, i, stack, currentSum):
currentSum += r.val
stack.append(r.val)
# 左右子树为空时,检验是否已经找到完整路径,输出路径
if not r.left and not r.right:
if currentSum == i:
for p in stack:
print(p)
# 左子树中找
if r.left:
findPath(r.left, i, stack, currentSum)
# 右子树中找
if r.right:
findPath(r.right, i, stack, currentSum)
# stack的最后一个节点的后续路径已检测完,删掉该节点
stack.pop()
def findAllPath(r, i):
if not root:
return None
stack = []
currentSum = 0
findPath(r, i, stack, currentSum)
18.二叉树的搜索区间
给定两个值 k1 和 k2(k1 < k2)和一个二叉查找树的根节点。找到树中所有值在 k1 到 k2 范围内的节点。
即打印所有x (k1 <= x <= k2) 其中 x 是二叉查找树的中的节点值。返回所有升序的节点值。
def searchHelper(root, k1, k2):
if not root:
return None
if root.val > k1:
searchHelper(root.left, k1, k2)
if root.val >= k1 and root.val <= k2:
result.append(root.val)
if root.val < k2:
serachHelper(root.right, k1, k2)
def searchRange(root, k1, k2):
result = list()
searchHelper(root, k1, k2)
return result
19.二叉树的层次遍历
def leverOrder(root):
result = list()
if not root:
return result
queue = list()
queue.append(root)
while queue:
size = len(queue)
level = list()
for i in range(size):
node = queue.pop(0)
level.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
result.extend(level)
return result
20.二叉树内两个节点的最长距离
二叉树中两个节点的最长距离可能有三种情况:
1.左子树的最大深度+右子树的最大深度为二叉树的最长距离
2.左子树中的最长距离即为二叉树的最长距离
3.右子树中的最长距离即为二叉树的最长距离
因此,递归求解即可
class Result:
def __init__(self, maxDistance=0, maxDepth=0):
self.maxDistance = maxDistance
self.maxDepth = maxDepth
def getMaxDistanceResult(root):
if not root:
empty = Result(0, -1)
return empty
lmd = getMaxDIstanceResult(root.left)
rmd = getMaxDistanceResult(root.right)
result = Result()
result.maxDepth = max(lmd.maxDepth, rmd.maxDepth) + 1
result.maxDistance = max(lmd.maxDepth + rmd.maxDepth, max(lmd.maxDistance, rmd.maxDistance))
return result
def getMaxDistance(root):
return getMaxDistanceResult(root).maxDistance
21.不同的二叉树
给出 n,问由 1…n 为节点组成的不同的二叉查找树有多少种?
def numTrees(n):
counts = [0]*(n+1)
counts[0] = 1
counts[1] = 1
for i in range(2, n+1):
for j in range(i):
counts[i] += counts[j] * counts[i-j-1]
return counts[n]
22.判断二叉树是否是合法的二叉查找树(BST)
一棵BST定义为:
节点的左子树中的值要严格小于该节点的值。
节点的右子树中的值要严格大于该节点的值。
左右子树也必须是二叉查找树。
一个节点的树也是二叉查找树。
lastVal = float('inf')
firstNode = True
def isValidBST(root):
if not root: # 空
return True
if not isValidBST(root.left): # 左子树是否合法
return False
if not firstNode and lastVal >= root.val: # lastVal是root的根节点的值
return False
firstNode = False
lastVal = root.val
if not isValidBST(root.right): # 右子树是否合法
return False
return True
这些全部看下来,对二叉树有一个基本的了解,二叉树的算法,核心的还是函数的那一套,什么时候程序触发什么,在二叉树算法里面,也就是说,
当一个根节点,左边没东西了,右边没东西了,(或者左边遍历完了,右边也遍历完了)你要怎么做?
当一个根节点,当左边没东西了(或者左边的东西已经访问过了),你要怎么做?
当一个根节点,当右边没东西了(或者右边的东西已经访问过了),你要怎么做?
这个就是核心点。

浙公网安备 33010602011771号