104. 二叉树的最大深度(Easy)
如果左子树和右子树的最大深度为 l 和 r,那么该二叉树的最大深度即为 max(l,r) + 1,左子树和右子树的最大深度又可以以同样的方式计算
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def maxDepth(self, root):
if root == None:
return 0
return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right))
时间复杂度:O(n),n 为二叉树节点的个数。每个节点被遍历一次
空间复杂度:O(height),height 表示二叉树的高度。递归函数需要栈空间,而栈空间取决于递归的深度。
110. 平衡二叉树(Easy)
有了计算节点高度的函数,即可判断二叉树是否平衡。是平衡树的条件是当前左右子树的高度差小于等于 1,且左右子树分别是平衡树
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def isBalanced(self, root):
def Depth(root):
if root == None:
return 0
return 1 + max(Depth(root.left), Depth(root.right))
if root == None:
return True
return abs(Depth(root.left) - Depth(root.right)) < 2 and self.isBalanced(root.left) and self.isBalanced(root.right)
617. 合并二叉树(Easy)
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def mergeTrees(self, t1, t2):
if t1 == None:
return t2
if t2 == None:
return t1
root = TreeNode(t1.val + t2.val)
root.left = self.mergeTrees(t1.left, t2.left)
root.right = self.mergeTrees(t1.right, t2.right)
return root
112. 路径总和(Easy)
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def hasPathSum(self, root, sum):
if root == None:
return False
if root.left == None and root.right == None and root.val == sum:
return True
return self.hasPathSum(root.left, sum-root.val) or self.hasPathSum(root.right, sum-root.val)
437. 路径总和 III(Medium)
# 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 pathSum(self, root, sum):
def pathSum_from_root(root, sum):
if root == None:
return 0
res = 0
if root.val == sum:
res += 1
res += pathSum_from_root(root.left, sum-root.val) + pathSum_from_root(root.right, sum-root.val)
return res
if root == None:
return 0
return self.pathSum(root.left, sum) + self.pathSum(root.right, sum) + pathSum_from_root(root, sum)
572. 另一个树的子树(Easy)
# 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 isSubtree(self, s, t):
def issame(s, t):
if s == None and t == None:
return True
if s == None or t == None:
return False
if s.val != t.val:
return False
return issame(s.left, t.left) and issame(s.right, t.right)
if s == None:
return False
return issame(s, t) or self.isSubtree(s.left, t) or self.isSubtree(s.right, t)
101. 对称二叉树(Easy)
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def isSymmetric(self, root):
def issame(s, t):
if s == None and t == None:
return True
if s == None or t == None:
return False
if s.val != t.val:
return False
return issame(s.left, t.right) and issame(s.right, t.left)
if root == None:
return True
return issame(root.left, root.right)
543. 二叉树的直径(Easy)
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def diameterOfBinaryTree(self, root):
self.res = 0
def Depth(root):
if root == None:
return 0
L = Depth(root.left)
R = Depth(root.right)
self.res = max(self.res, L + R)
return 1 + max(L, R)
Depth(root)
return self.res
226. 翻转二叉树(Easy)
方法一:递归
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def invertTree(self, root):
if root == None:
return root
node = root.left
root.left = self.invertTree(root.right)
root.right = self.invertTree(node)
return root
方法二:迭代
中序遍历的思想,按照二叉树的层次,将每一行节点压入队列中,取出元素时交换左右子树
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def invertTree(self, root):
if root == None:
return root
queue = [root]
while queue:
current = queue.pop(0)
tmp_node = current.left
current.left = current.right
current.right = tmp_node
if current.left:
queue.append(current.left)
if current.right:
queue.append(current.right)
return root
111. 二叉树的最小深度(Easy)
方法一:深度优先搜索
求树的高度的变形,最小路径等于左子树的最小路径与右子树最小路径的较小值加1。注意:如果有一棵子树为空,只算另外一棵不为空的子树。
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def minDepth(self, root):
if root == None:
return 0
L = self.minDepth(root.left)
R = self.minDepth(root.right)
if L == 0 or R == 0:
return 1 + L + R
return min(L, R)+1
方法二:广度优先搜索
类似与层序遍历,当我们找到一个叶子节点时,直接返回这个叶子节点的深度。
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def minDepth(self, root):
if root == None:
return 0
queue = collections.deque([(root, 1)])
while queue:
node, depth = queue.popleft()
if node.left == None and node.right == None:
return depth
if node.left:
queue.append([node.left, depth+1])
if node.right:
queue.append([node.right, depth+1])
return 0
404. 左叶子之和(Easy)
方法一:递归
对于一个节点
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def sumOfLeftLeaves(self, root):
if root == None:
return 0
left_leavers_sum = 0
if root.left:
if root.left.left == None and root.left.right == None:
left_leavers_sum += root.left.val
else:
left_leavers_sum += self.sumOfLeftLeaves(root.left)
if root.right:
left_leavers_sum += self.sumOfLeftLeaves(root.right)
return left_leavers_sum
方法二:迭代
层序遍历,当节点为左节点且为叶子节点时,进行累加
将节点放入队列时,左节点标记为 1,右节点标记为 0
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def sumOfLeftLeaves(self, root):
left_leavers_sum = 0
if root == None or (root.left == None and root.right == None):
return 0
queue = collections.deque([(root, 1)])
while queue:
current, isleft = queue.popleft()
if current.left == None and current.right == None and isleft:
left_leavers_sum += current.val
if current.left:
queue.append([current.left, 1])
if current.right:
queue.append([current.right, 0])
return left_leavers_sum
687. 最长同值路径(Easy)
在递归函数中,首先对其左右子结点调用递归函数,得到其左右子树的最大相同值路径长度,接下来看当前结点和其左右子结点之间的关系了,如果其左子结点存在且和当前节点值相同,则左侧长度加 1,否则以当前节点为根节点的左侧相同节点的最大路径长度为 0;同理,如果其右子结点存在且和当前节点值相同,右侧长度加 1,否则为0。若该结点最长相同路径 left_arrow + right_arrow 大于 res,更新 res。
调用当前节点值的函数返回 left_arrow 和 right_arrow 中的较大值,原因如下:递归函数返回的是以该结点为终点的最长路径长度,这样回溯时,还可以继续连上其父结点。
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def longestUnivaluePath(self, root):
self.res = 0
def arrow_len(root):
if root == None:
return 0
left_length = arrow_len(root.left)
right_length = arrow_len(root.right)
left_arrow, right_arrow = 0, 0
if root.left and root.left.val == root.val:
left_arrow = left_length + 1
if root.right and root.right.val == root.val:
right_arrow = right_length + 1
self.res = max(self.res, left_arrow + right_arrow)
return max(left_arrow, right_arrow)
arrow_len(root)
return self.res
337. 打家劫舍 III(Medium)
将问题分解为偷根节点与不偷根节点,取二者最大值。偷根节点时,总钱数等于根节点钱数加上左右子树均不偷根节点钱数之和。
不偷根节点时,左右两颗子树可以偷根节点,也可以不偷,取两颗子树的最大值,加和。
left_rob 表示偷左子节点,left_no 表示不偷左子节点
right_rob 表示偷右子节点,right_no 表示不偷右子节点
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def rob(self, root):
def _rob(root):
if root == None: return 0, 0
left_rob, left_no = _rob(root.left)
right_rob, right_no = _rob(root.right)
return root.val + left_no + right_no, max(left_rob, left_no) + max(right_rob, right_no)
return max(_rob(root))
671. 二叉树中第二小的节点(Easy)
如果根节点有子节点,则将左右结点的值保存,如果左节点值等于根节点的值,说明一定不是第二小的结点值,以左子节点为根节点寻找第二小的结点值(递归调用)。右侧也相同。在左右子树找到的第二小结点后进行比较,若都不为-1,返回较小的那个,若其中一个为-1,返回另外一个,否则不存在,返回-1。
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def findSecondMinimumValue(self, root):
if root == None:
return -1
if root.left == None and root.right == None:
return -1
leftval = root.left.val
rightval = root.right.val
if leftval == root.val:
leftval = self.findSecondMinimumValue(root.left)
if rightval == root.val:
rightval = self.findSecondMinimumValue(root.right)
if leftval != -1 and rightval != -1:
return min(leftval, rightval)
if leftval != -1:
return leftval
return rightval
方法二:遍历,求非根节点值之外的最小值
也可以直接遍历,求非根节点值之外的最小值,这里我用了中序遍历,每遍历一层,将非根节点值保存,挑出最小值,如果遍历之后该值存在,则返回,不存在返回 -1
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def findSecondMinimumValue(self, root):
queue = collections.deque()
queue.append(root)
res = float('inf')
while queue:
big = []
queue_len = len(queue)
for _ in range(queue_len):
current = queue.popleft()
if current.val > root.val:
big.append(current.val)
if current.left:
queue.append(current.left)
queue.append(current.right)
if big:
big = sorted(big)
res = min(res, big[0])
return -1 if res == float('inf') else res
也可以使用前序遍历,保存根节点的值为 small,第二小的数定义为 second,初始化为 -1,如果第一次遇见不等于根节点的数值,直接赋值给 second,不是第一次遇见不等于根节点的数值,如果比 second 小,更新 second
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def findSecondMinimumValue(self, root):
self.second = -1
self.small = root.val
def preview(root):
if root == None:
return
if self.second == -1 and root.val != self.small:
self.second = root.val
if self.second != -1 and root.val != self.small:
self.second = min(root.val, self.second)
preview(root.left)
preview(root.right)
if root == None:
return -1
preview(root)
return self.second
894. 所有可能的满二叉树(Medium)
方法:递归
令 f(N) 作为所有含 N 个结点的可能的满二叉树的列表。
每个满二叉树含有 3 个或更多结点,在其根结点处有 2 个子结点。这些子结点 left 和 right 本身就是满二叉树。因此,对于 N≥3,我们可以设定如下的递归策略:f(N) = [对于所有的 x,所有的树的左子结点来自 f(x) 而右子结点来自 f(N−1−x)]。
最后,我们应该缓存函数 f(N) 之前的结果,这样我们就不必在递归中重新计算它们。
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
memo = {
0:[], 1:[TreeNode(0)]}
def allPossibleFBT(self, N):
if N in self.memo:
return self.memo[N]
res = []
for i in range(1, N, 2):
for left in self.allPossibleFBT(i):
for right in self.allPossibleFBT(N-i-1):
root = TreeNode(0)
root.left = left
root.right = right
res.append(root)
return res
"""
:type N: int
:rtype: List[TreeNode]
"""
102. 二叉树的层序遍历(Medium)
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
ans = []
if not root:
return ans
queue = [root]
while queue:
n = len(queue)
level = []
for _ in range(n):
child = queue.pop(0)
level.append(child.val)
if child.left:
queue.append(child.left)
if child.right:
queue.append(child.right)
ans.append(level)
return ans
637. 二叉树的层平均值(Easy)
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def averageOfLevels(self, root):
res = list()
queue = collections.deque()
queue.append(root)
while queue:
len_queue = len(queue)
sum = 0.0
for _ in range(len_queue):
current = queue.popleft()
sum += current.val
if current.left:
queue.append(current.left)
if current.right:
queue.append(current.right)
res.append(sum/len_queue)
return res
513. 找树左下角的值(Easy)
从右到左的层序遍历,访问的最后一个元素就是左下角的节点
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def findBottomLeftValue(self, root):
queue = collections.deque()
queue.append(root)
while queue:
cur = queue.popleft()
if cur.right:
queue.append(cur.right)
if cur.left:
queue.append(cur.left)
return cur.val
103. 二叉树的锯齿形层次遍历(Medium)
用两个栈分别保存从左向右和从右向左的元素。栈中每次保存二叉树一层的数据。
第 1,3,5 等奇数行的数据从左向右依次入栈,2,4,6 偶数行的数据从右向左依次入栈,后入栈的先出栈
# 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 preorderTraversal(self, root):
res = list()
stack = []
p = root
while(p or stack):
while(p):
res.append(p.val)
stack.append(p)
p = p.left
p = stack.pop()
p = p.right
return res
时间复杂度:O(n),其中 n 是二叉树的节点数,每一个节点恰好被遍历一次。
空间复杂度:O(n),为迭代过程中栈的开销,平均情况下为 O(logn),最坏情况下树呈现链状,为 O(n)
144. 二叉树的前序遍历(Medium)
问题分析:
先序、中序和后序遍历过程:遍历过程中经过结点的路线一样,只是访问各结点的时机不同。
# 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 preorderTraversal(self, root: TreeNode) -> List[int]:
res = []
stack = []
p = root
while(p != None or len(stack) != 0):
if p != None:
res.append(p.val)
stack.append(p)
p = p.left
else:
top = stack.pop()
p = top.right
return res
94. 二叉树的中序遍历(Medium)
# 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 inorderTraversal(self, root):
res = list()
stack = []
p = root
while(p or stack):
while p:
stack.append(p)
p = p.left
p = stack.pop()
res.append(p.val)
p = p.right
return res
"""
:type root: TreeNode
:rtype: List[int]
"""
145. Binary Tree Postorder Traversal(Hard)
问题分析:
要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。如果P不存在左孩子和右孩子,则可以直接访问它;或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了 每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。
# 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 postorderTraversal(self, root: TreeNode) -> List[int]:
res = []
if root == None:
return res
stack = []
stack.append(root)
cur = None
pre = None
while stack:
cur = stack[-1]
if (cur.left == None and cur.right == None) or ((cur.left == pre or cur.right == pre) and pre != None):
res.append(cur.val)
pre = cur
stack.pop()
else:
if cur.right:
stack.append(cur.right)
if cur.left:
stack.append(cur.left)
return res