代码随想录二叉树part04|110.平衡二叉树、257. 二叉树的所有路径、404.左叶子之和、513.找树左下角的值、112.路径总和、106.从中序与后序遍历序列构造二叉树
一刷直接过,二刷有精力的时候 再去掌握迭代法。
110.平衡二叉树
判断 左子树和右子树是否小于等于1
如何判断呢?
判断每个节点的左右子树的高度差是否超过1
高度 vs 深度:
高度:距离叶子节点的距离
深度:距离根节点的距离
高度 深度 3 3 1 / \ 9 20 2 2 / \ 15 7 1 3 后序遍历 前序遍历
(后序通过左右孩子返回给父节点,层层向上返回,所以可以求高度;
前序 中左右 向下遍历,不向上返回结果)
伪代码c++
:
int getHeight( node ){
if (node == NULL) return 0; // 空节点的高度是0
leftHeight = getHeight(node->left); // 左
if(leftHeight==-1) return -1; // 左子树不是平衡二叉树
rightHeight = getHeight(node->right); // 右
if(rightHeight==-1) return -1; // 右子树不是平衡二叉树
int result;
if(abs(rightHeight - leftHeight) > 1) return -1;
else return 1 + max(leftHeight, rightHeight);
}
需要额外写一个辅助函数(用于计算高度的函数)
python代码
:
class Solution:
def isBalanced(self, root: Optional[TreeNode]) -> bool:
if self.getHeight(root) == -1:
return False
else:
return True
def getHeight(self, root):
if not root:
return 0
leftHeight = self.getHeight(root.left)
if leftHeight == -1:
return -1
rightHeight = self.getHeight(root.right)
if rightHeight == -1:
return -1
if abs(rightHeight - leftHeight) > 1:
return -1
else:
return 1 + max(rightHeight, leftHeight)
257. 二叉树的所有路径 回溯法 需要再回顾
思路
:
递归法使用前序遍历,
回溯法,
伪代码(C++)
:
void travesal (TreeNode node, void<int> &path, vector<string> &result){
// 中 要写在前面,否则会落下叶子节点
path.push_back(node->val)
if(node->left==NULL && node->right==NULL){ //遍历到叶子节点回溯
result.push_back(path); // path需要进行进一步处理,这里简化
return;
}
// 左
if(node->left){
travesal(node->left, path, result); // 递归
path.pop_back(); //回溯
}
// 右
if(node->right){
travesal(node->right, path, result);
path.pop_back();
}
}
python代码
:
class Solution:
def traversal(self, cur, path, result):
path.append(cur.val)
if not cur.left and not cur.right:
spath = '->'.join(map(str, path))
result.append(spath)
if cur.left:
self.traversal(cur.left, path, result)
path.pop()
if cur.right:
self.traversal(cur.right, path, result)
path.pop()
def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
result = list()
path = list()
if not root:
return result
self.traversal(root, path, result)
return result
404.左叶子之和 写完了 但还不太懂
思路
:
左叶子节点:叶子节点中 && 父节点的左孩子
要通过父节点判断子节点是不是我们要收集的元素,一层一层收集左叶子之和,向上返回
用后序遍历代码相对简洁 + 回溯
伪代码(C++)
:
int traversal( TreeNode node ) {
if(node==NULL) return 0; // 空节点
if(node->left==NULL && node->right==NULL) return 0; // 叶子节点
// 左
int leftNum = traversal(node->left);
if(node->left != NULL && node->left->left==NULL && node->left->right==NULL){
leftNum = node->left->val;
}
// 右
int rightNum = traversal(node->right);
// 中
int sum = leftNum + rightNum;
return sum;
}
python代码
:
class Solution:
def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
if not root: return 0
if not root.left and not root.right: return 0
leftnum = self.sumOfLeftLeaves(root.left)
if root.left and not root.left.left and not root.left.right:
leftnum = root.left.val
rightnum = self.sumOfLeftLeaves(root.right)
Sum = leftnum + rightnum
return Sum
513.找树左下角的值
思路
:
迭代法
递归法
深度最大的叶子节点,使用前中后序遍历都可(只要先遍历左节点)
伪代码(C++)
:
int maxDepth = INT_MIN; // 记录最大深度
int result; // 叶子结点的值
void trversal(root, depth){
if(root->left==NULL && root->right==NULL)
if(depth>maxDepth) {
maxDepth = depth;
result = root->val;
}
}
// 左:只要左在右的前面即可
if(root->left){
depth++;
traversal(node->left, depth);
depth--; // 回溯
} / 这3行可以缩写为: traversal(node->left, depth+1)
// 右
if(root->right){
depth++;
traversal(node->right, depth);
depth--;
}
}
python代码
:
class Solution:
def traversal(self, root, depth):
if not root.left and not root.right:
if depth > self.maxDepth:
self.maxDepth = depth
self.result = root.val
if root.left:
depth += 1
self.traversal(root.left, depth)
depth -= 1
if root.right:
depth += 1
self.traversal(root.right, depth)
depth -= 1
return self.result
def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
self.maxDepth = 0
self.result = root.val
return self.traversal(root, 1)
112. 路径总和
思路
:
注意: 必须要到叶子节点的总和,return的写法,递归完后也要return
if traversal(node->left, count) return true;
没有中的处理逻辑,前中后序遍历都可以
没有必要全都遍历完,找到一条路径立刻返回即可
伪代码(C++)
:
bool traversal(TreeNode node, int count); // 传入目标值,做减法
if(node->left==NULL && node->right==NULL && count==0) // 到叶子节点,减为0了
return true;
if(node->left==NULL && node->right==NULL && count!=0)
return false;
if(node->left){
count -= node->left->val;
if traversal(node->left, count) return true;
count += node->left->val;//回溯
}
if(node->right){
count -= node->right->val;
if traversal(node-right, count) return true;
count += node->right->val; // 回溯
}
return false;
}
python代码
:
# 我的代码
class Solution:
def traversal(self, node, thesum):
if not node.left and not node.right and thesum == self.targetSum:
return True
if node.left:
thesum += node.left.val
if self.traversal(node.left, thesum):
return True
thesum -= node.left.val
if node.right:
thesum += node.right.val
if self.traversal(node.right, thesum):
return True
thesum -= node.right.val
return False
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if not root: return False
self.targetSum = targetSum
return self.traversal(root, root.val)
路径总和Ⅱ
代码注意要点:
- self.result.append(path[:]) 而不是 self.result.append(path)
列表是可变数据结构,加:切片是深拷贝;不加的话是浅拷贝,之后就变了 - self.result 设置为类的私有属性
class Solution:
def traversal(self, node, thesum, path):
# print(path)
# print(thesum)
# print(self.result)
print('-------------')
if not node.left and not node.right and thesum==self.targetSum:
self.result.append(path[:])
return
if not node.left and not node.right:
return
if node.left:
path.append(node.left.val)
thesum += node.left.val
self.traversal(node.left, thesum, path)
thesum -= node.left.val
path.pop()
if node.right:
path.append(node.right.val)
thesum += node.right.val
self.traversal(node.right, thesum, path)
thesum -= node.right.val
path.pop()
return
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
self.result = []
path = []
self.targetSum = targetSum
if not root: return self.result
path.append(root.val)
self.traversal(root, root.val, path)
return self.result
路径总和Ⅲ
思路与前面的不一样了,注意!
使用递归法,深度优先遍历,不需要回溯!分别遍历以每一个节点为开始可能的路径。
注意递归的结束条件,如果这个节点的值即为我们要找的值,count+=1
class Solution:
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> int:
def rootSum(root, targetSum):
if not root:
return 0
ret = 0
if root.val == targetSum:
ret += 1
ret += rootSum(root.left, targetSum - root.val)
ret += rootSum(root.right, targetSum - root.val)
return ret
if root is None:
return 0
ret = rootSum(root, targetSum)
ret += self.pathSum(root.left, targetSum)
ret += self.pathSum(root.right, targetSum)
return ret
106.从中序与后序遍历序列构造二叉树
思路
:
递归
伪代码(C++)
:
python代码
:
class Solution:
def buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode:
# 第一步: 特殊情况讨论: 树为空. (递归终止条件)
if not postorder:
return None
# 第二步: 后序遍历的最后一个就是当前的中间节点.
root_val = postorder[-1]
root = TreeNode(root_val)
# 第三步: 找切割点.
separator_idx = inorder.index(root_val)
# 第四步: 切割inorder数组. 得到inorder数组的左,右半边.
inorder_left = inorder[:separator_idx]
inorder_right = inorder[separator_idx + 1:]
# 第五步: 切割postorder数组. 得到postorder数组的左,右半边.
# ⭐️ 重点1: 中序数组大小一定跟后序数组大小是相同的.
postorder_left = postorder[:len(inorder_left)]
postorder_right = postorder[len(inorder_left): len(postorder) - 1]
# 第六步: 递归
root.left = self.buildTree(inorder_left, postorder_left)
root.right = self.buildTree(inorder_right, postorder_right)
# 第七步: 返回答案
return root