代码随想录刷题系列文章目录
二叉树篇
文章目录
110.平衡二叉树
dfs错误思路
首先,紧跟昨日的二叉树的最大深度,最小深度这些题的思路
这道题上来我就明白了要用后序的遍历方式,但是我的错路是直接找root 的左右子树,找他们各自的最大高度,如果最大高度的绝对值在1之内,返回true
def isBalanced(self, root: Optional[TreeNode]) -> bool:
if not root: return True
def getheight(node):
if not node: return 0
left = getheight(node.left)
right = getheight(node.right)
return 1 + max(left, right)
left = getheight(root.left)
right = getheight(root.right)
if abs(left-right) <= 1:
return True
return False
但是这种思路,有一个弊端
就是这种情况
很明显这种是不对的,因为子树就不是平衡的
dfs正确的 能过所有例子的写法
所以,如果递归过程中子树就不是平衡二叉树,最后结果也就不是平衡二叉树
所以要在geiheight的同时,子树不达标的就return 一个-1,不能继续进入递归
def getheight(self, node):
if not node: return 0
lefthei = self.getheight(node.left)
if lefthei == -1: return -1
righthei = self.getheight(node.right)
if righthei == -1: return -1
res = 0
if abs(lefthei-righthei) > 1: res = -1
else: res = 1 + max(lefthei, righthei)
return res
def isBalanced(self, root: Optional[TreeNode]) -> bool:
if self.getheight(root) != -1: return True
else: return False
这种写法,就是在找高度的同时,如果发现子树不平衡,就返回一个-1了
bfs写法
class Solution:
def isBalanced(self, root: Optional[TreeNode]) -> bool:
if not root:
return True
height_map = {}
stack = [root]
while stack:
node = stack.pop()
if node:
stack.append(node)
stack.append(None)
if node.left: stack.append(node.left)
if node.right: stack.append(node.right)
else:
real_node = stack.pop()
left, right = height_map.get(real_node.left, 0), height_map.get(real_node.right, 0)
if abs(left - right) > 1:
return False
height_map[real_node] = 1 + max(left, right)
return True
257. 二叉树的所有路径 (dfs 回溯)
这道题目要求从根节点到叶子的路径,所以需要前序遍历,这样才方便让父节点指向孩子节点,找到对应的路径。
前序的dfs写法:
- 确定递归参数
要传入根节点,记录每一条路径的path,和存放结果集的result - 确定递归终止条件
本题要找到叶子节点,就开始结束的处理逻辑了(把路径放进result里)那么什么时候算是找到了叶子节点? 是当 cur不为空,其左右孩子都为空的时候,就找到叶子节点。 - 确定单层递归逻辑
这里的根左右这个逻辑中,由于我们找到叶子结点之后,就把整个路径加进结果里;所以说,我们操作根这个步骤,要放在出口之前,不然的话 叶子结点加不进path
回溯的代码以后就按着这种模板写吧
# 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 binaryTreePaths(self, root: TreeNode) -> List[str]:
path = ''
result = []
if not root: return result
self.traversal(root, path, result)
return result
def traversal(self, cur: TreeNode, path: str, result: List[str]) -> None:
path += str(cur.val) # 根 为什么写在这里,因为最后一个节点也要加入到path中
# 若当前节点为leave,直接输出
if not cur.left and not cur.right:
result.append(path)
if cur.left:
# + '->' 是隐藏回溯
self.traversal(cur.left, path + '->', result)
if cur.right:
self.traversal(cur.right, path + '->', result)
然后,回溯这个过程为什么能省略,原因一定要看引用
404.左叶子之和
dfs写法 后序遍历
递归的参数没有什么可说的
首先是递归的出口,要注意是判断左叶子,不是二叉树左侧节点,所以不要上来想着层序遍历。左叶子结点的判断:结点的左子树不空,且左子结点没有孩子
其次就是每层的递归逻辑,可以说这道题的递归写法的逻辑是后序遍历的,左右子树的左叶子结点,分别统计完,用一个值加起来
def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
leftsum = self.sumOfLeftLeaves(root.left)
if root.left != None and root.left.left == None and root.left.right == None:
leftsum = root.left.val
rightsum = self.sumOfLeftLeaves(root.right)
sum_ = leftsum + rightsum
return sum_
迭代写法
class Solution:
def sumOfLeftLeaves(self, root: TreeNode) -> int:
"""
Idea: Each time check current node's left node.
If current node don't have one, skip it.
"""
stack = []
if root:
stack.append(root)
res = 0
while stack:
# 每次都把当前节点的左节点加进去.
cur_node = stack.pop()
if cur_node.left and not cur_node.left.left and not cur_node.left.right:
res += cur_node.left.val
if cur_node.left:
stack.append(cur_node.left)
if cur_node.right:
stack.append(cur_node.right)
return res