110.平衡二叉树
文档讲解:代码随想录
题目链接:. - 力扣(LeetCode)
一棵高度平衡二叉树定义为:一个二叉树每个节点的左右两个子树的高度差的绝对值不超过1。
二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数。
方法一
递归的三要素:
第一要素:明确这个函数想要干什么
输入一个节点,返回这个以这个节点为根节点的二叉树是否是平衡二叉树
第二要素:寻找递归结束条件
①如果节点是空,那么return true
②如果以这个节点为根节点的左右子树的高度超过了1,那么就return false
第三要素:找出函数的等价关系式
如果根节点的左右子树满足高度要求,这个树也不一定是平衡二叉树,如下图
也就是说我们判断完以根节点为根节点的二叉树满足平衡二叉树的要求之后还要去看它的左右子树是不是也都满足平衡二叉树的要求
class Solution:
def isBalanced(self, root: Optional[TreeNode]) -> bool:
if not root:
return True
###计算深度的代码有问题
left_depth = self._depth(root.left)
right_depth = self._depth(root.right)
if abs(left_depth-right_depth)>1:
return False
left_node = self.isBalanced(root.left)
right_node = self.isBalanced(root.right)
return left_node and right_node
#私有方法,定义一个计算二叉树高度的方法,传入:根节点,输出:二叉树的高度
def _depth(self,node):
if not node:
return 0
left_depth = self._depth(node.left)
right_depth = self._depth(node.right)
return max(left_depth,right_depth) + 1
方法二
递归的三要素:
第一要素:明确这个函数想要干什么
返回传入根节点的二叉树的高度,但是如果左右子树的返回值有-1,或者左右子树的高度差大于1就返回-1
第二要素:寻找递归结束条件
如果node是空,则返回0
第三要素:找出函数的等价关系式
二叉树的高度即为左右子二叉树高度的较大值加1
### 方法二
class Solution:
def isBalanced(self, root: Optional[TreeNode]) -> bool:
if not root:
return True
if self._depth(root) != -1:
return True
else:
return False
#定义一个计算二叉树高度的方法,传入:根节点,输出:二叉树的高度,如果高度差大于1那么就是-1
def _depth(self,node):
#返回高度,如果高度差大于1 则返回-1
if not node:
return 0
left_depth = self._depth(node.left)
right_depth = self._depth(node.right)
#如果有负一就证明不是一颗平衡二叉树,直接返回-1
if left_depth== -1 or right_depth == -1:
return -1
elif abs(left_depth-right_depth)>1:
return -1
else:
return max(left_depth,right_depth) + 1
注意: 这个递归与之前写的递归不太一样,这个多了一些判断和设置返回值的步骤
代码随想录中说到的“中”都是指处理的步骤,左右都是递归遍历的步骤
257. 二叉树的所有路径
没有太懂
文档讲解:代码随想录
题目链接:. - 力扣(LeetCode)
递归的三要素:
第一要素:明确这个函数想要干什么
传入根节点,找到以根节点开头的每一条路径的path并存放到最后的结果集result中
找出二叉树中从根节点到每个叶子节点的路径,并添加到path中,最后将路径表示为字符串存储在结果列表中返回
第二要素:寻找递归结束条件
找到叶子节点,就开始结束的处理逻辑了(把路径放进result里)。即如果这个节点的左右节点都为空,那么就将路径放入path中
第三要素:找出函数的等价关系式
先将当前的根节点的值加入到path路径中,如果当前节点已经是叶子节点,那么就结束了。
如果不是叶子节点,如果有左节点那么我们需要在path路径中继续加入以左节点为根节点的path路径,也就是调用了递归函数。(当遍历到叶子节点时,我们就遍历完了这一条路径,并且将其加入到了result数组中)
接下来我们要遍历另一条路径,此时我们就需要弹出path中的最后一个节点。加入以原来path中倒数第二个节点为开始节点的path路径,此时要向右递归,因为左边我们已经遍历过了
class Solution:
def binaryTreePaths(self, root):
#递归函数,作用:记录传入的根节点到一个叶子节点的一条路径path,并保存到结果集result
def traversal(node,path,result):
path.append(node.val)
#叶子节点,终止条件
if not node.left and not node.right:
spath = '->'.join(map(str,path))
result.append(spath)
return
##递推
if node.left:
traversal(node.left,path,result)
#遍历完了一条路径之后
path.pop()#回退一个路径
if node.right:
traversal(node.right,path,result)
path.pop() #回溯
if not root:
return []
path = []
result = []
traversal(root,path,result)
return result
404.左叶子之和
文档讲解:代码随想录
题目链接:. - 力扣(LeetCode)
叶子节点:左右孩子都是空的节点
什么是左叶子:这个节点是父孩子的左节点
可以知道一个节点是不是叶子节点,但是如何知道一个节点是不是左叶子呢 ,即它是不是父节点的左孩子呢。所以我们遍历到一个节点的时候,要先看它的左节点是否为空。左节点的左如果不为空再看它的右节点是否为空,如果满足这个条件那么这个节点就是左叶子节点
递归的三要素:
第一要素:明确这个函数想要干什么
找到以该节点为根节点的二叉树的左叶子节点之和
第二要素:寻找递归结束条件
传入节点,如果这个节点为空,就可以直接返回0
如果这个节点的左右孩子都是空,也返回0
第三要素:找出函数的等价关系式
接下来,我们找到左子树的左叶子之和和右子树的左叶子之和相加,并且要判断该节点的左节点是否是左叶子,如果是,要加入到左叶子之和中,因为如果不加入的话,下次递归会把这个作为叶子节点,而不是左叶子节点,会返回0。最终就是以该节点为根节点的二叉树的左叶子之和
class Solution:
#函数的作用:返回以该节点为根节点的二叉树的左叶子之和
def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
#终止条件
value = 0
if root == None:
return 0
if root.left == None and root.right == None:
return 0
if root.left!=None and root.left.left == None and root.left.right == None:
value = root.left.val #这里不可以直接返回,这里只能说明该节点的左子节点的值要加入,但是该节点的右子树可能还有左叶子
#递推逻辑
left_sum = self.sumOfLeftLeaves(root.left)
right_sum = self.sumOfLeftLeaves(root.right)
return left_sum+right_sum+value