LeetCode 226.翻转二叉树:
思路:
遍历二叉树,将每个结点的左右子树进行翻转。因此只要是能将结点的左右子树进行翻转的遍历方式都可以
- 前序
# 递归
# 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 invertTree(self, root):
"""
:type root: TreeNode
:rtype: TreeNode
"""
if not root: return root
root.left, root.right = root.right, root.left
self.invertTree(root.left)
self.invertTree(root.right)
return root
# 迭代
class Solution(object):
def invertTree(self, root):
stack = []
if root: stack.append(root)
while stack:
cur = stack.pop()
if cur.right: stack.append(cur.right)
if cur.left: stack.append(cur.left)
cur.left, cur.right = cur.right, cur.left
return root
# 统一迭代
class Solution(object):
def invertTree(self, root):
stack = []
if root: stack.append(root)
while stack:
cur = stack.pop()
if cur: # 入栈左右结点和当前结点做标记
if cur.right: stack.append(cur.right)
if cur.left: stack.append(cur.left)
stack.append(cur)
stack.append(None)
else: # 遇到标记处理当前结点
cur = stack.pop()
cur.left, cur.right = cur.right, cur.left
return root
- 中序
#递归
class Solution(object):
def invertTree(self, root):
# 中序递归
if not root: return root
# 先处理左子树
self.invertTree(root.left)
root.left, root.right = root.right, root.left # 交换左右结点
# 此时的左子树是交换前的右子树,处理新左子树
self.invertTree(root.left)
return root
# 非统一迭代
class Solution(object):
def invertTree(self, root):
stack = []
cur = root
while cur or stack:
if cur:
stack.append(cur)
cur = cur.left
else:
cur = stack.pop()
cur.left, cur.right = cur.right, cur.left
cur = cur.left
return root
- 层序遍历
class Solution(object):
def invertTree(self, root):
queue = deque()
if root: queue.append(root)
while queue:
q_size = len(queue)
for _ in range(q_size):
cur = queue.popleft()
if cur.left: queue.append(cur.left)
if cur.right: queue.append(cur.right)
cur.left, cur.right = cur.right, cur.left
return root
感悟:
抓住主要特点:给定结点,交换结点的左右子树
LeetCode 101.对称二叉树:
思路:
- 层序遍历?
如下图所示,两颗树的层序遍历相同,但是明显树1不是对称树,树2是对称树。但是层序遍历时使用None对二叉树进行填充,从而判断当前层是否对称时用到None。
层序遍历的算法的修改:当前结点存在时,左右孩子结点均入队,每层使用列表保存当前层的全部结点(包括None)的值,然后判断列表是否对称
from collections import deque
class Solution(object):
def isSymmetric(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
if not root:
return True
queue = deque()
queue.append(root.left)
queue.append(root.right)
while queue:
q_size = len(queue)
if q_size % 2 != 0: # 剪枝
return False
level_c = [] # 保存的是结点的值而不是结点
for _ in range(q_size):
cur = queue.popleft()
if cur: # 不为None才入栈左右孩子
# cur的左右孩子均入栈(不管是否为空)
queue.append(cur.left)
queue.append(cur.right)
level_c.append(cur.val)
else:
level_c.append(-101) # None对应的值不在结点值的范围内
if level_c != level_c[::-1]:
return False
return True
- 广义上的后序遍历
判断树是否为轴对称,需要判断根的左右子树是否对称,比较左右子树的外侧是否相等、内侧是否相等,事实上是判断左子树的外侧与右子树的外侧是否相等,接着判断左子树的内侧与右子树的内侧是否相等,接着对判断结果进行汇总。
- 采用递归的方式
① 传入参数与返回值:需要传入左子树的判断结点和右子树的判断结点,函数返回判断结果
bool compare(TreeNode left, TreeNode right){
}
② 边界条件(直接返回的条件):判断left和right是否对称
# 左空右不空 || 左不空右空 false
if ((left == NULL && right != NULL) || (left != NULL && right == NULL) return false
# 左右均为空 true
else if(left == NULL && right == NULL) return true
# 左右均不为空且值不同 false
else if(left->val != right->val) return false
③ 正常递归下去:判断外侧是否相等,内侧是否相等,并对结果进行整理
bool outside = compare(left->left, right->right)
bool inside = compare(left->right, right->left)
bool result = outside && inside
return bool
# 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 isSymmetric(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
if not root:
return True
return self.compare(root.left, root.right)
def compare(self, left, right):
# 边界条件
if (left and not right) or (not left and right): # 有一个为空另一个不为空
return False
elif not left and not right: # 均为空
return True
elif left.val != right.val: # 均不为空且值不等
return False
# 正常递归下去
outside = self.compare(left.left, right.right)
inside = self.compare(left.right, right.left)
return (inside and outside)
- 迭代方式(使用栈/队列)
和递归的思路相同,从栈/队列中弹出两个要比较的结点,对当前结点的值进行比较后外侧结点成对、内侧结点成对入队(None也要进)
# 队列
from collections import deque
class Solution(object):
def isSymmetric(self, root):
if not root:
return True
queue = deque()
# 出队顺序:左右
queue.append(root.left)
queue.append(root.right)
while queue:
left = queue.popleft()
right = queue.popleft()
# 比较当前结点是否对称
if not left and not right:
continue
elif not left or not right: # 一个为空,另一个不为空
return False
elif left.val != right.val: # 均不为空,且值不同
return False
# 均不为空且值相同,外侧结点成对、内侧结点成对入队
queue.append(left.left) # 外侧
queue.append(right.right)
queue.append(left.right) # 内侧
queue.append(right.left)
return True
# 栈
class Solution(object):
def isSymmetric(self, root):
if not root:
return True
# 弹出顺序:左右
stack = [root.right, root.left]
while stack:
left = stack.pop()
right = stack.pop()
# 比较当前结点
if not left and not right: # 均为空
continue
elif not left or not right: # 只有一个为空,另一个不为空
return False
elif left.val != right.val: # 均不为空且值不等
return False
# 成对压栈结点
stack.append(right.right) # 外侧
stack.append(left.left)
stack.append(right.left) # 内侧
stack.append(left.right)
return True
感悟:
内外侧进行判断,先判断当前左右结点的左右子树是否相等,再在当前结点进行整理。(层序遍历解决方法进一步需要再研究一下)
LeetCode 104.二叉树的最大深度:
思路:
- 递归后序遍历求最大深度
class Solution(object):
def maxDepth(self, root):
"""
:type root: TreeNode
:rtype: int
"""
def getdepth(node):
if not node:
return 0
left_depth = getdepth(node.left) # 左
right_depth = getdepth(node.right) # 右
depth = 1 + max(left_depth, right_depth) # 根
return depth
tree_depth = getdepth(root)
return tree_depth
- 层序遍历求最大深度(模板)
from collections import deque
class Solution(object):
def maxDepth(self, root):
queue = deque()
if root: queue.append(root)
level = 0
while queue:
q_size = len(queue)
level += 1
for _ in range(q_size):
cur = queue.popleft()
if cur.left: queue.append(cur.left)
if cur.right: queue.append(cur.right)
return level
感悟:
求深度注意只有根节点时深度为0还是1
LeetCode 111.二叉树的最小深度:
思路
- 递归后序遍历
需要注意深度是到叶子结点的深度,None不存在深度
class Solution(object):
def minDepth(self, root):
"""
:type root: TreeNode
:rtype: int
"""
def getDepth(node):
if not node:
return 0
left_depth = getDepth(node.left)
right_depth = getDepth(node.right)
if node.left and not node.right:
return left_depth + 1
elif not node.left and node.right:
return right_depth + 1
else:
depth = 1 + min(left_depth, right_depth)
return depth
depth = getDepth(root)
return depth
- 层序遍历
每层从左到右遍历过程中,遇到的第一个叶子结点的深度就是最小深度
from collections import deque
class Solution(object):
def minDepth(self, root):
queue = deque()
if root: queue.append(root)
min_level = 0
while queue:
q_size = len(queue)
min_level += 1
for _ in range(q_size):
cur = queue.popleft()
# 从左向右遍历,遇到的第一个叶子节点的层为最小深度
if not cur.left and not cur.right: return min_level
else:
if cur.left : queue.append(cur.left)
if cur.right: queue.append(cur.right)
return min_level
感悟:
深度不算None结点,只算叶子结点
学习收获:
利用递归的后序遍历求解与层序遍历,二叉树需要用到遍历的题目需要首先弄清楚要用什么遍历方式