写代码的第十三天
110.平衡二叉树
本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点的左右两个子树的高度差的绝对值不超过1。
思路(递归)
求平衡二叉树,所以要做的就是不停的判断从根结点开始她的左右子树是不是平衡二叉树,也就是递归判断她的左右子树高度差绝对值是不是超过一,那么就需要计算每个结点左右子树的高度差,所以需要递归来计算高度差。设置一个函数gethigh用来计算高度。
错误第一版:其实最开始在getHIgh函数中想把if abs(left - right) > 1: return -1,设置为return False,但是在上面函数调用的时候是需要返回值的,那么得让这个返回值是一致的,既然下面要计算的是高度,全都是数字,那么就让if abs(left - right) > 1:也返回一个数字,这个数字设置为小于0的数字更好区分。根据错误的信息我们可以发现,在这段代码中,我们并没有判断子树的子树等等这些是否是平衡二叉树,一旦出现不平衡的,直接就是false了也就是gethigh函数中的-1,我们只判断了跟结点的子树是不是平衡二叉树。
gethigh函数要么返回的是空的时候0,要么返回的是不平衡的时候-1,要么是最大高度,所以在这里-1指的就是不平衡的时候的一个代替而已,left和right的计算中也是要调用gethigh函数的,所以返回值也是上面三种,那么也就是说当其为-1的时候,就不用再继续向下递归了,已经出现了不平衡现象,直接返回-1即可。
class Solution:
def isBalanced(self, root: Optional[TreeNode]) -> bool:
if root == None:
return True
result = self.getHigh(root)
if result >= 0:
return True
else:
return False
def getHigh(self,node):
if node == None:
return 0
left = self.getHigh(node.left)
right = self.getHigh(node.right)
if abs(left - right) > 1:
return -1
else:
return 1 + max(left,right)
正确代码:
class Solution:
def isBalanced(self, root: Optional[TreeNode]) -> bool:
result = self.getHigh(root)
if result >= 0:
return True
else:
return False
def getHigh(self,node):
if node == None:
return 0
left = self.getHigh(node.left)
if left == -1:
return -1
right = self.getHigh(node.right)
if right == -1:
return -1
if abs(left - right) > 1:
return -1
else:
return 1 + max(left,right)
257. 二叉树的所有路径
思路
从跟结点开始遍历,跟结点先处理,然后才是其他的结点,所以是中左右的遍历形式,也就是前序遍历。将遍历过的结点全都放在路径里面,当到达叶子结点的时候,证明一条路径已经完成,此时将最后的叶子结点弹出,也就是图中所体现的回溯,回到上一级结点之后,继续向右遍历,如果有右子树那就继续遍历,直到整颗树遍历完成。
错误版本一:最后的输出值中间是有符号的,所以要spath = ‘->’.join(map(str,path)),还要注意path需要的是结点的值,而不是整个结点!!!!
class Solution:
def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
if root == None:
return result
path = []
result = []
self.traversal(root,path,result)
return result
def traversal(self,node,path,result):
path.append(node)
if node.left == None and node.right == None:
result.append(path)
if node.left:
left = self.traversal(node.left,path,result)
path.pop()
if node.right:
right = self.traversal(node.right,path,result)
path.pop()
正确代码:
class Solution:
def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
if root == None:
return result
path = []
result = []
self.traversal(root,path,result)
return result
def traversal(self,node,path,result):
path.append(node.val)
if node.left == None and node.right == None:
spath = '->'.join(map(str,path))
result.append(spath)
if node.left:
left = self.traversal(node.left,path,result)
path.pop()
if node.right:
right = self.traversal(node.right,path,result)
path.pop()
404.左叶子之和
左叶子的明确定义:节点A的左孩子不为空,且左孩子的左右孩子都为空(说明是叶子节点),那么A节点的左孩子为左叶子节点
思路(递归)
1、参数是root
2、终止条件:当结点的左右孩子都为空了,那这个时候就证明已经到了叶子结点,此时停止。但是此时你没有办法判断这个结点是不是左叶子结点,所以还需要一个条件,就是从这个结点的父结点开始判断,判断父结点的左孩子是否为空。
3、单层递归逻辑:找到每个结点的左子树的左叶子和右子树的左叶子,然后求和。
错误第一版:我好像还是没太搞懂递归,就是知道不停的调用自身函数,但总是很蒙圈为什么调用了最后就有数值啊啊啊啊啊啊啊
在这段代码里面,我只是判断了root的几个情况,然后就开始递归根结点的左子树和右子树,但是题目的要求是计算左叶子结点之和啊,整片代码里面没有体现求和的过程啊,也没有体现找叶子结点的过程
我还是没搞懂递归。。。。。。。很难受
class Solution:
def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
if root == None:
return 0
if root.left == None and root.right == None:
return 0
left = self.sumOfLeftLeaves(root.left)
right = self.sumOfLeftLeaves(root.right)
sums = left + right
return sums
正确代码:
class Solution:
def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
if root == None:
return 0
if root.left == None and root.right == None:
return 0
left = self.sumOfLeftLeaves(root.left)
if root.left != None and root.left.left == None and root.left.right == None:
left = root.left.val
right = self.sumOfLeftLeaves(root.right)
sums = left + right
return sums
222.完全二叉树的节点个数
思路(层序)
import collections
class Solution:
def countNodes(self, root: Optional[TreeNode]) -> int:
result = 0
if root == None:
return 0
queue = collections.deque()
queue.append(root)
while len(queue) != 0:
res = []
for _ in range(len(queue)):
node = queue.popleft()
res.append(node.val)
if node.left != None:
queue.append(node.left)
if node.right != None:
queue.append(node.right)
result += len(res)
return result
思路(普通二叉树求法)
一看就会,自己写就废,我真服了。。。
class Solution:
def countNodes(self, root: Optional[TreeNode]) -> int:
if root == None:
return 0
left = self.countNodes(root.left)
right = self.countNodes(root.right)
result = 1 + left + right
return result
思路(完全二叉树)
完全二叉树的结点个数,其实除了最下面的一层上面的全都是满二叉树,满二叉树的结点数就很好求了(满二叉树的深度为n,结点个数为2**n-1个)。所以这个题如果用递归并且利用上满二叉树的性质的做法就应该是,采用后序遍历,递归的判断左子树右子树是不是满二叉树,满二叉树就按照公式计算。
如何判断是不是满二叉树?就是看这个树里面的所有子树是不是左右子树的高度相等,如果相等就是满,不相等就不是。但是这个题的基础是在完全二叉树的基础上,所以我们只需要判断从根结点到最左侧叶子结点的高度和跟结点到最右侧叶子结点的的高度即可,中间的可以不判断,因为完全二叉树中间一定有结点。
误区:我一直在想我们找的都是满二叉树,那肯定有不是满二叉树的,这种情况怎么办呢?其实在递归中,叶子结点就是满二叉树的一种情况,其左右子树全为空,所以就算遇到了不是满二叉树的情况,只要继续向下遍历,让下层的满二叉树算好结点数返回给上一层,上一层按照这个数字加一就完成了不是满二叉树的情况。(递归还是没理解透哇,道阻且长。。。)
正确代码:
class Solution:
def countNodes(self, root: Optional[TreeNode]) -> int:
if root == None:
return 0
left = root.left
right = root.right
leftheigh = 1
rightheigh = 1
while left:
left = left.left
leftheigh += 1
while right:
right = right.right
rightheigh += 1
if leftheigh == rightheigh:
return 2 ** leftheigh - 1
return self.countNodes(root.left) + self.countNodes(root.right) + 1