leetcode:617. 合并二叉树
问题描述:给定两个二叉树,合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。
解法:指定其中一个树,如果到达叶子节点,则下一步返回另一个树的结点(包含这个节点的左右子树)
时间复杂度:log(n)
class Solution(object):
def mergeTrees(self, t1, t2):
"""
:type t1: TreeNode
:type t2: TreeNode
:rtype: TreeNode
"""
# 如果其中一个二叉树终止,则直接返回另一个
if not t1:
return t2
if not t2:
return t1
t1.val = t1.val + t2.val
t1.left = self.mergeTrees(t1.left, t2.left)
t1.right = self.mergeTrees(t1.right, t2.right)
return t1
剑指offer:树的子结构
问题描述:输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
解法:首先找到树A中(与树B的根结点的值相同)的结点,判断是不是有相同结构,然后递归判断左右结点,递归的终止条件是到达了树A或者树B的叶结点
时间复杂度:log(n)
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def HasSubtree(self, pRoot1, pRoot2):
# 如果树A与树B任意一个为空,则肯定不存在子结构
res = False
# 找到树A中(与树B的根结点的值相同)的结点
if pRoot1 and pRoot2:
if pRoot1.val == pRoot1.val:
res = self.check_structure(pRoot1, pRoot2)
if res == False:
res = self.HasSubtree(pRoot1.left, pRoot2)
# 遍历完左子树,如果没有找到就继续遍历右子树
if res == False:
res = self.HasSubtree(pRoot1.right, pRoot2)
return res
# 找递归判断左右结点,递归的终止条件是到达了树A或者树B的叶结点
def check_structure(self, root1, root2):
# 到达了树B的叶结点
if root2 is None:
return True
# 到达了树A的叶结点
if root1 is None:
return False
# 树A与树B的当前结点的值不相同
if root1.val != root2.val:
return False
left_check = self.check_structure(root1.left, root2.left)
right_check = self.check_structure(root1.right, root2.right)
return left_check and right_check
剑指offer:二叉树的镜像
问题描述:请完成一个函数,输入一个二叉树,该函数输出它的镜像。
解法:先序遍历(根左右)树的每个节点,如果遍历到的结点有子结点,就交换它的两个子结点。当交换完所有非叶子结点的左右子结点之后,就得到了树的镜像。
时间复杂度:log(n)
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回镜像树的根节点
def Mirror(self, root):
if root is None:
return root
root.left, root.right = root.right, root.left
self.Mirror(root.left)
self.Mirror(root.right)
return root
剑指offer:重建二叉树
问题描述:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树
解法:根据前序遍历(根左右)找到根节点,中序遍历的根节点划分了左右子树。递归分别返回左、右子树的前序遍历和中序遍历
时间复杂度:n*log(n)
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回构造的TreeNode根节点
def reConstructBinaryTree(self, pre, tin):
if len(pre) == 0:
return None
if len(pre) == 1:
# 按照树节点的结构定义!!!
return TreeNode(pre[0])
# 找到根节点,按照树节点的结构定义!!!
root = TreeNode(pre[0])
# 在中序遍历中找到根节点,并且划分左\右子树
root_p = tin.index(root.val)
root.left = self.reConstructBinaryTree(pre[1:root_p+1], tin[:root_p])
# 注意下标:tin[root_p+1:]
root.right = self.reConstructBinaryTree(pre[root_p+1:], tin[root_p+1:])
return root
剑指offer:二叉树的深度
问题描述:输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
解法:最长路径的深度=最长路径的叶结点数目,如果树只有一个结点,深度为1。如果有左右子树,则为左右的深度较大值加1。
时间复杂度:
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def TreeDepth(self, pRoot):
if pRoot is None:
return 0
l = self.TreeDepth(pRoot.left)
r = self.TreeDepth(pRoot.right)
return l+1 if l > r else r+1
剑指offer:平衡二叉树
问题描述:输入一棵二叉树,判断该二叉树是否是平衡二叉树。平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
解法:后序遍历(左右根),遍历节点的时候记录它的深度
时间复杂度:O(n)
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 如果每个节点都是平衡的,最后返回的是深度
def get_depth(self, root):
if root is None:
return 0
left = self.get_depth(root.left)
right = self.get_depth(root.right)
# 如果某个子树不平衡,则返回-1
if left == -1 or right == -1:
return -1
return max(left, right) + 1 if abs(right - left) < 2 else -1
def IsBalanced_Solution(self, pRoot):
return self.get_depth(pRoot) != -1
剑指offer:从上往下打印二叉树
问题描述:从上往下打印出二叉树的每个节点,同层节点从左至右打印。
解法:前序遍历(根左右),放入根节点,然后把它的左右节点放入队列。先入先出能够保证子树节点进入之后,同层的节点先打印。
时间复杂度:O(log(n))
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回从上到下每个节点值列表,例:[1,2,3]
def PrintFromTopToBottom(self, root):
# 异常值处理
if root is None:
return []
queue = [root]
output = []
while queue:
if queue[0].left:
queue.append(queue[0].left)
if queue[0].right:
queue.append(queue[0].right)
# 根节点的值放入输出序列
output.append(queue[0].val)
# 队列头部取出根节点
queue.pop(0)
return output
剑指offer:二叉搜索树的后序遍历序列
问题描述:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
解法:后序遍历,左右根。后序遍历序列的最后一个元素为根节点,序列可以分为左子树+右子树。如果在子树中发现与根节点大小关系不一致的节点,则返回错误。
二叉搜索树的性质:若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。
时间复杂度:O(log(n))
class Solution:
def VerifySquenceOfBST(self, sequence):
# 输入[]
if not sequence:
return False
if len(sequence) == 1:
return True
# !!! 当根节点只有一个左子树时,右子树的遍历会根据split指向的元素开始。如果初始化为0,那么右子树会错误地读入左子树
split = len(sequence)-1
# 找到根节点
root = sequence[-1]
# 找到划分点
for _ in range(0, len(sequence)-1):
if sequence[_] > root:
split = _
break
# 确认后半段都比root大
for _ in range(split, len(sequence)-1):
if sequence[_] < root:
return False
# 递归检查前半段和后半段
left = True
# 前半段至少有两个元素,才递归
if split > 0:
left = self.VerifySquenceOfBST(sequence[:split])
right = True
# 后半段至少有两个元素,才递归
if split < len(sequence) - 1:
right = self.VerifySquenceOfBST(sequence[split:-1])
return left and right
a = Solution()
print(a.VerifySquenceOfBST([]))
剑指offer:二叉树中和为某一值的路径
问题描述:输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径
解法:(当前输入值的更新=当前输入值-根节点值)递归遍历左右子树,返回所有满足的路径。
class Solution:
# 返回二维列表,内部每个列表表示找到的路径
def FindPath(self, root, expectNumber):
if not root:
return []
# 叶子节点且等于输入值,返回当前节点
if not root.left and not root.right and root.val == expectNumber:
return [[root.val]]
# 非叶子节点,遍历它的左右节点
left = self.FindPath(root.left, expectNumber - root.val)
right = self.FindPath(root.right, expectNumber - root.val)
return [[root.val] + i for i in left+right]
剑指offer:二叉搜索树与双向链表
问题描述:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
解法:中序遍历,把左子树的最右边一个结点返回,把右子树的最左边结点返回,然后根节点再连接这两个结点,形成双向链表
时间复杂度:
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def Convert(self, pRootOfTree):
# 把左子树的最右边一个结点返回,把右子树的最左边结点返回,然后根节点再连接这两个结点
if not pRootOfTree:
return pRootOfTree
if not pRootOfTree.left and not pRootOfTree.right:
return pRootOfTree
left = pRootOfTree.left
# 遍历左子树
self.Convert(left)
# 找到左子树的最右边一个结点
# 'NoneType' object has no attribute 'left'
if left:
while left.right:
left = left.right
# 连接根节点,形成双向链表
# 'NoneType' object has no attribute 'left'
left.right, pRootOfTree.left = pRootOfTree, left
right = pRootOfTree.right
# 遍历右子树
self.Convert(right)
# 找到右子树的最左边结点
if right:
while right.left:
right = right.left
# 连接根节点,形成双向链表
right.left, pRootOfTree.right = pRootOfTree, right
# 返回最小值的节点,位于左子树的最左边
head = pRootOfTree
while head.left:
head = head.left
return head
leetcode:101. 对称二叉树
问题描述:给定一个二叉树,检查它是否是镜像对称的。例如,二叉树 [1,2,2,3,4,4,3]
是对称的。
解法:镜像的条件为,它们的两个根结点具有相同的值,且每个树的右子树都与另一个树的左子树镜像对称
时间复杂度:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
if not root:
return True
def balance(r1, r2):
if r1 is None and r2 is None:
return True
if r1 is None or r2 is None:
return False
return r1.val == r2.val and balance(r1.left, r2.right) and balance(r1.right, r2.left)
return balance(root.left, root.right)
leetcode:437. 路径总和 III
问题描述:给定一个二叉树,它的每个结点都存放着一个整数值。找出路径和等于给定数值的路径总数。路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
解法:保存从根节点到路径的和列表,每一步计算等于sum的个数。dfs递归时,之前的和依次加上当前节点的值,再添加当前节点。
class Solution(object):
def pathSum(self, root, sum):
"""
:type root: TreeNode
:type sum: int
:rtype: int
"""
if not root:
return 0
# target 所有路径所能构成的和列表
def dfs(node, target):
if not node:
return 0
# 左右的值默认为0
l, r = 0, 0
# 之前的和依次加上当前节点的值,再添加当前节点
target = [node.val] + [_ + node.val for _ in target]
# 递归
l = dfs(node.left, target)
r = dfs(node.right, target)
# 计算当前的路径和等于给定数值的个数
return target.count(sum) + l + r
return dfs(root, [])
剑指offer:543. 二叉树的直径
问题描述:给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过根结点。
解法:对于每一个当前节点,选择左、右节点中最大的长度,然后加上1(当前路径),则是当前的最长路径深度。全局变量dis为直径,每次取左、右节点深度的和。
class Solution(object):
def __init__(self):
self.dis = 0
def diameterOfBinaryTree(self, root):
"""
:type root: TreeNode
:rtype: int
"""
if not root:
return 0
def diameter(node):
if node is None:
return 0
l = diameter(node.left)
r = diameter(node.right)
self.dis = max(l+r, self.dis)
# 选择左右节点中最大的长度,然后加上1(当前路径)
return max(l,r) + 1
diameter(root)
return self.dis
leetcode:538. 把二叉搜索树转换为累加树
问题描述:给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater Tree),使得每个节点的值是原来的节点值加上所有大于它的节点值之和。
解法:先遍历右子树,储存根节点,再遍历左子树
class Solution(object):
def convertBST(self, root):
# 从最右的节点开始,到根,到根的左节点
self.num = 0
def search(root):
if not root:
return
search(root.right)
self.num += root.val
root.val = self.num
search(root.left)
return root
return search(root)
leetcode:
问题描述:
解法:
时间复杂度: