100. 相同的树
给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
示例:
输入:p = [1,2,3], q = [1,2,3]
输出:true
思路1:递归
终止条件:p节点和q节点都为空或者两者之一为空,或者两者值不等。再次比较p节点和q节点的左孩子,以及比较p节点和q节点的右孩子
# 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 isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
"""
递归停止条件::p节点和q节点都为空或者两者之一为空,或者两者值不等
"""
if p == None and q == None:
return True
if p == None or q == None:
return False
if p.val != q.val:
return False
# 比较p和q的左孩子与右孩子,如果左孩子不相等了就不需要比较右孩子,短路效应
return self.isSameTree(p.left,q.left) and self.isSameTree(p.right,q.right)
思路2:迭代
- 首先用一个栈来保存根节点p,q。接着不断遍历这个栈。
- 我们从栈中拿出两个元素进行比较,如果这两个元素不等(一个是空一个不为空,或者两个节点的值不等),就直接返回false。如果这两个节点的值相等,就继续把 p 节点的左孩子,q节点的左孩子放入栈中;再把p节点的右孩子,q节点的右孩子放入栈中。重复这个步骤,直到栈为空。
- 如果整个循环遍历完了,说明两个树的元素都是相等的,返回 true。
# 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 isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
"""
迭代解决
"""
# 用栈来保存p和q遍历时的节点
stack = [(p,q)]
while stack:
a,b = stack.pop()
# 如果a,b为空,则继续下一轮比较
if a == None and b == None:
continue
if a and b and a.val == b.val:
stack.append((a.left,b.left))
stack.append((a.right,b.right))
else:
return False
# 循环结束时,stack为空
return True
101. 对称二叉树
给定一个二叉树,检查它是否是镜像对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
思路:
如果一个树的左子树与右子树镜像对称,那么这个树是对称的。因此,该问题可以转化为:两个树在什么情况下互为镜像?
如果同时满足下面的条件,两个树互为镜像:
- 它们的两个根结点具有相同的值。
- 每个树的右子树都与另一个树的左子树镜像对称。
如何去判断二叉树是镜像对称?
- 根节点为null,直接返回True;
- 当根节点不为null时,判断左右子树是否对称:判断root.left跟root.right节点值是否相同
- 判断root.left的左子树是否与root.right的右子树对称,判断root.left的右子树是否与root.right的左子树对称
终止条件:left 和right不等,或者left 和right都为空
# 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 isSymmetric(self, root: TreeNode) -> bool:
if root == None:
return True
def dfs(left,right):
"""
终止条件:left 和right不等,或者left 和right都为空
"""
if left == None and right == None:
return True
if left == None or right == None:
return False
if left.val != right.val:
return False
# 单个镜像不对称时,则镜像非对称
return dfs(left.left,right.right) and dfs(left.right,right.left)
# 递归比较左右子树
return dfs(root.left,root.right)
思路2:迭代
这里使用一个队列
- 首先从队列中拿出两个节点(left 和right)比较
- 将left 的left节点和right 的right 节点放入队列,将left 的right节点和right 的left节点放入队列,然后进行迭代
# 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 isSymmetric(self, root: TreeNode) -> bool:
# 使用队列-先进先出
if root == None:
return True
q = [(root.left,root.right)]
while q != []:
left,right = q.pop(0)
if left == None and right == None:
continue
if left and right and left.val == right.val:
# 将左右孩子添加入队列
q.append((left.left,right.right))
q.append((left.right,right.left))
else:
return False
return True
思路3:
这里使用一个栈
- 首先从队列中拿出两个节点(left 和right)比较
- 将left 的left节点和right 的right 节点放入队列,将left 的right节点和right 的left节点放入栈,然后进行迭代
# 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 isSymmetric(self, root: TreeNode) -> bool:
# 使用栈-后进先出
if root == None:
return True
stack = [(root.left,root.right)]
while stack != []:
left,right = stack.pop()
if left == None and right == None:
continue
if left and right and left.val == right.val:
# 将左右孩子添加入栈
stack.append((left.left,right.right))
stack.append((left.right,right.left))
else:
return False
return True
110. 平衡二叉树
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
示例:
输入:root = [3,9,20,null,null,15,7]
输出:true
思路1:自顶向下暴力递归
构造一个获取当前节点最大深度的方法depth(),通过比较左右子树最大高度差
abs(self.depth(root.left) - self.depth(root.right))
,来判断以此节点为根节点下是否是二叉平衡树;
- 从顶至底深度优先遍历DFS,以每个节点为根节点,递归判断是否是平衡二叉树
若所有根节点都满足平衡二叉树性质,则返回True ;
若其中任何一个节点作为根节点时,不满足平衡二叉树性质,则返回 False。
本方法产生大量重复的节点访问和计算,最差情况下时间复杂度O(N^2)。
# 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 isBalanced(self, root: TreeNode) -> bool:
# 自顶向下暴力递归
# 递归判断每一个子树是否是平衡二叉树
# 递归计算每一个二叉树的深度
if root == None:
return True
if abs(self.depth(root.left) - self.depth(root.right)) <= 1:
# 递归判断左右子树是否是平衡树
return self.isBalanced(root.left) and self.isBalanced(root.right)
# 递归判断是否是平衡二叉树的终止条件:高度差大于1
else:
return False
# 计算二叉树的深度
def depth(self,root):
# 终止条件为根节点为空或者只有根节点
if root == None:
return 0
if root.left == None and root.right == None:
return 1
# 有一个节点不为空时,递归计算其深度
if root.left != None or root.right != None:
return max(self.depth(root.left),self.depth(root.right)) + 1
思路2:自底向上(提前阻断)
对二叉树做深度优先遍历DFS,
终止条件:当DFS 越过叶子节点时,返回高度O;
返回值:
从底至顶,返回以每个节点root为根节点的子树最大高度(左右子树中最大的高度值加1,max(left,right)+1
))
当我们发现有一例左/右子树高度差>1的情况时,代表此树不是平衡树,返回-1
当发现不是平衡树时,后面的高度计算都没有意义了,因此一路返回– 1,避免后续多余计算。
最差情况是对树做一遍完整DFS,时间复杂度为O(N)。
# 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 isBalanced(self, root: TreeNode) -> bool:
"""
递归+提前阻断
"""
if self.depth(root) == -1:
return False
else:
return True
def depth(self,root):
if root == None:
return 0
depth_left = self.depth(root.left)
# 提前阻断
if depth_left == -1:
return -1
depth_right = self.depth(root.right)
# 提前阻断
if depth_right == -1:
return -1
if abs(depth_left - depth_right) <= 1:
return 1 + max(depth_left,depth_right)
# 提前阻断
else:
return -1
104. 二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7]
返回它的最大深度 3 。
思路1:迭代
迭代实现其实就是广度遍历,遍历每一层的节点高度,然后求得最深的一个节点的高度,就是整个树的高度了。
# 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 maxDepth(self, root: TreeNode) -> int:
"""
利用栈来迭代遍历
"""
if root == None:
return 0
stack = [(1,root)]
depth = 0
while stack:
# 从栈中弹出元素
cur_depth,node = stack.pop()
if node:
# 比较当前深度与depth,并记录当前最大深度
depth = max(cur_depth,depth)
# 将左节点放入栈
stack.append((cur_depth+1,node.left))
# 将右节点放入栈
stack.append((cur_depth+1,node.right))
return depth
思路2:递归
递归终止条件:当节点为空时返回
再次递归计算max(左节点最大高度,右节点最大高度)+1。+1
相当于把根节点也算上
# 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 maxDepth(self, root: TreeNode) -> int:
"""递归"""
# 如果节点为空,那么深度为0
if root == None:
return 0
# 继续递归左子树与右子树,最后算深度时,把根节点算上
return max(self.maxDepth(root.left),self.maxDepth(root.right)) + 1
111. 二叉树的最小深度
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明:叶子节点是指没有子节点的节点。
示例:
输入:root = [3,9,20,null,null,15,7]
输出:2
思路1:迭代
层次遍历二叉树,如果树为空,直接返回0。否则将树和深度值1入队列,逐一弹出队列中节点:
若某节点左右子树均为空,此节点即为叶子节点,我们将它的深度与最小深度min_depth进行比较,更新最小深度。
若其存在子树,则将其存在的子树和子树深度入队列。
实际上,因为层次遍历是一层一层遍历的,所以第一个叶子节点即为最小深度的叶子节点,直接返回其深度即可。这样就不用遍历所有的节点。
# 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:
"""使用队列保存"""
if root == None:
return 0
queue = [(root,1)]
while queue:
# 先从队列中弹出元素
node,depth = queue.pop(0)
# 当叶子节点出现时,不在继续操作
if node.left == None and node.right == None:
return depth
# 左节点不为空,则将左节点加入队列
if node.left != None:
queue.append((node.left,depth+1))
if node.right != None:
queue.append((node.right,depth+1))
思路2:递归
递归解法的关键是搞清楚递归结束条件:
当root 节点左右孩子都为空(叶子节点)时,返回1
当root节点左右孩子有一个为空时,返回不为空的孩子节点的深度
当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 minDepth(self, root: TreeNode) -> int:
"""递归"""
if root == None:
return 0
# 当root 节点左右孩子都为空(叶子节点)时,返回1
if root.left == None and root.right == None:
return 1
# 当root节点左右孩子有一个为空时,返回不为空的孩子节点的深度
if root.left == None or root.right == None:
return max(self.minDepth(root.left),self.minDepth(root.right)) + 1
# 当root节点左右孩子都不为空时,返回左右孩子较小深度的节点值
if root.left != None and root.right != None:
return min(self.minDepth(root.left),self.minDepth(root.right)) +1
662. 二叉树最大宽度
给定一个二叉树,编写一个函数来获取这个树的最大宽度。树的宽度是所有层中的最大宽度。这个二叉树与满二叉树(full binary tree)结构相同,但一些节点为空。
每一层的宽度被定义为两个端点(该层最左和最右的非空节点,两端点间的null节点也计入长度)之间的长度。
示例:
输入:
1
/ \
3 2
/ \ \
5 3 9
输出: 4
解释: 最大值出现在树的第 3 层,宽度为 4 (5,3,null,9)。
思路:迭代层次遍历
因为两端点间的None值也计入,所以这里我们不能简单的统计每一层的节点数,这里我们可以考虑给树中的每一个节点进行编号,根节点为1,然后如果是左节点,值为根节点的二倍;如果是右节点,值为根节点的二倍加一。
这里用层次遍历,采用一个队列记录每一个节点的节点以及号码,一层的首末元素的编号差就是该层的最大宽度。
# 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 widthOfBinaryTree(self, root: TreeNode) -> int:
# 判断根节点是否为空
if root == None:
return 0
queue = [(root,1)]
width = 0
# 层次遍历,每一层whie判断一次
while queue:
length = len(queue)
for i in range(length):
node,nums = queue.pop(0)
# 分别记录每一层第一个节点的编号与最后一个节点的编号
if i == 0:
first_num = nums
if i == length-1:
last_num = nums
# 更新宽度
width = max(width,last_num - first_num + 1)
# 左右子树入队
if node.left != None:
queue.append((node.left,2*nums))
if node.right != None:
queue.append((node.right,2*nums+1))
return width
如果对您有帮助,麻烦点赞关注,这真的对我很重要!!!如果需要互关,请评论或者私信!