LeetCode 110.平衡二叉树:
思路:(暂时只有递归)
明确一下二叉树的深度和高度
- 结点的深度:根结点到该结点的最长简单路径边的条数(leetcode中是结点数)
- 结点的高度:当前结点到叶子结点的最长简单路径边的条数(leetcode中是结点数)
- 深度是从根节点开始算,也就是从上至下;高度是从叶子结点开始算,也就是从下至上(适合后序遍历)
递归三部曲:
后序遍历,判断左右子树是否为平衡二叉树,接着判断以当前结点为根节点的二叉树是否为平衡二叉树
① 传入参数和返回的变量:
传入结点node,返回结点的高度。对于如果以当前结点为根节点的二叉树已经不是平衡二叉树,那么返回高度无意义了,可以直接返回 -1 表示当前结点不是平衡二叉树。
② 边界条件(直接返回的条件):
还是node == None
③ 正常递归下去的过程:
判断左右子树是否为平衡二叉树,接着判断以当前结点为根节点的二叉树是否为平衡二叉树
# 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 isBalanced(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
def getHeight(node):
if not node:
return 0
left_h = getHeight(node.left)
if left_h == -1: return -1 #若左子树不是平衡二叉树
right_h = getHeight(node.right)
if right_h == -1: return -1 # 若右子树不是平衡二叉树
else: # 左右子树都是平衡二叉树
if abs(left_h - right_h) > 1: # 以当前结点为根的二叉树不是平衡二叉树
return -1
else:
height = 1 + max(left_h, right_h)
return height
height = getHeight(root)
if height != -1:
return True
else:
return False
感悟:
二叉树的高度和深度的区别,以及递归三部曲
LeetCode 257.二叉树的所有路径:
思路:(暂时是递归)
回溯,递归三部曲:
① 传入参数和返回变量:传入node,当前记录的路径path和全部叶子结点的路径result
② 边界条件:此处的边界条件应当是node为叶子结点,因为路径记录的是根->叶子的路径,应当在遇到叶子结点时进行处理
③ 正常进行的条件:前序遍历,将当前结点加入path后,递归遍历左右子树(存在的话),遍历完成后回溯
class Solution(object):
def binaryTreePaths(self, root):
"""
:type root: TreeNode
:rtype: List[str]
"""
path, result = [], []
if not root:
return []
self.traversal(root, path, result)
return result
def traversal(self, node, path, result):
path.append(node.val)
if not node.left and not node.right: # 叶子结点
s_path = '->'.join(map(str, path))
result.append(s_path)
return
if node.left:
self.traversal(node.left, path, result)
path.pop() # 回溯
if node.right:
self.traversal(node.right, path, result)
path.pop() # 回溯
感悟:
回溯的一点知识
LeetCode 404.左叶子之和:
思路:
- 递归
# 递归1:判断 当前结点的左孩子 是否为左叶子
# ① 传入参数node,返回左叶子结点之和
# ② 边界条件:当前结点为None和叶子结点
# ③ 正常递归:根据当前结点的左孩子是否为左叶子来得到左子树的左叶子结点之和;得到右子树的左叶子结点之和;最后加和并返回
class Solution(object):
def sumOfLeftLeaves(self, root):
"""
:type root: TreeNode
:rtype: int
"""
leaveValue = self.get_left(root)
return leaveValue
def get_left(self, node):
# 边界
if not node:
return 0
if not node.left and not node.right:
return 0
# 左子树的左叶子结点之和:需要根据左孩子结点是否为左叶子结点来求
if node.left and not node.left.left and not node.left.right:
leftValue = node.left.val
else:
leftValue = self.get_left(node.left)
# 右子树直接求其左叶子结点之和
rightValue = self.get_left(node.right)
sum_val = leftValue + rightValue
return sum_val
# 递归2:判断 当前结点 是否为左叶子结点
# ① 传入参数:node, isleft
class Solution(object):
def sumOfLeftLeaves(self, root):
left_leaves_sum = self.get_leaves(root, False)
return left_leaves_sum
def get_leaves(self, node, isleft):
# 边界条件:叶子结点,左叶子返回值,右叶子返回0
if not node.left and not node.right:
if isleft: return node.val
else: return 0
# 正常递归下去
flag_isleft = True
leaves_left_sum = leaves_right_sum = 0
if node.left:
leaves_left_sum = self.get_leaves(node.left, flag_isleft) # 左
if node.right:
leaves_right_sum = self.get_leaves(node.right, not flag_isleft) # 右
leaves_sum = leaves_left_sum + leaves_right_sum # 根
return leaves_sum
- 迭代
使用栈来进行前序遍历,同时判断当前结点的左孩子结点是否为左叶子结点
class Solution(object):
def sumOfLeftLeaves(self, root):
if not root:
return 0
stack = [root]
result = 0
while stack:
node = stack.pop()
if node.left and not node.left.left and not node.left.right: # 左叶子结点
result += node.left.val
if node.right: stack.append(node.right)
if node.left: stack.append(node.left)
return result
感悟:
判断结点的左孩子结点是否为左叶子结点要少一层递归
LeetCode 222.完全二叉树的节点个数:
思路:
- 借助完全二叉树的性质
首先,深度为h(h从1开始)的满二叉树的节点个数为 2^h - 1,而完全二叉树,如果是满二叉树:2 ^ h - 1;如果不是满二叉树,递归求左右子树(递归到最后一定是满二叉树,因为只有一个结点的二叉树就是满二叉树)。
小tips:计算 2^ h = 2 << h - 1,因此在计算深度h时可以从0开始,从而直接用 2 << h;完全二叉树一直向左 or 右遍历到叶节点就可以得到当前二叉树的深度
# 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 countNodes(self, root):
"""
:type root: TreeNode
:rtype: int
"""
if not root:
return 0
# 求左右子树的深度(包括了根结点的)
leftHeight, rightHeight = 0, 0 # 2^h = 2 << (h - 1)。
left, right = root.left, root.right
# 完全二叉树,一直向左就能得到深度
while left:
left = left.left
leftHeight += 1
# 一直向右就能得到右边的深度
while right:
right = right.right
rightHeight += 1
if leftHeight == rightHeight: # 满二叉树
return (2 << leftHeight) - 1
# 不是满二叉树,左右递归
left_sum = self.countNodes(root.left)
right_sum = self.countNodes(root.right)
return left_sum + right_sum + 1
- 一般二叉树的方法:深度优先遍历和广度优先遍历
# 层序遍历
from collections import deque
class Solution(object):
def countNodes(self, root):
queue = deque()
nodes = 0
if root: queue.append(root)
while queue:
q_size = len(queue)
for _ in range(q_size):
cur = queue.popleft()
nodes += 1
if cur.left: queue.append(cur.left)
if cur.right: queue.append(cur.right)
return nodes
#递归-前序遍历(后序遍历也行)
class Solution(object):
def countNodes(self, root):
if not root:
return 0
leftTreeNodes = self.countNodes(root.left)
rightTreeNodes = self.countNodes(root.right)
return leftTreeNodes + rightTreeNodes + 1
#迭代-前序遍历
class Solution(object):
def countNodes(self, root):
stack = []
nodes = 0
if root: stack.append(root)
while stack:
cur = stack.pop()
nodes += 1
if cur.left: stack.append(cur.left)
if cur.right: stack.append(cur.right)
return nodes
感悟:
利用好完全二叉树的性质,不是满二叉树向下递归直到为满二叉树
学习收获:
学到了二叉树的高度和深度以及使用回溯找到二叉树的所有路径,解题时需要看清楚题目以及掌握完全二叉树的性质来解题