代码随想录算法训练营第15天 | 二叉树部分: 110. 平衡二叉树,257. 二叉树的所有路径,404. 左叶子之和
110. 平衡二叉树
给定一个二叉树,判断它是否是高度平衡的二叉树。本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
思路:左右子树在是平衡二叉树的前提下,两者的高度差的绝对值小于等于1
返回值 参数: 返回值为高度差 参数为二叉树
终止条件:节点为空
单层循环:首先考虑左右子树的平衡性 计算左子树的高度,右子树的高度,然后进行判断,需要几个计算高度的函数
思路是对的,虽然写的代码有点长,确实是先要保证左子树和右子树的平衡性,再去比较整个二叉树的平衡性,这边当时在犹豫
public boolean isBalanced(TreeNode root) {
if(root==null){
return true;
}
//左右子树的平衡
if(!isBalanced(root.left)){
return false;
}
if(!isBalanced(root.right)){
return false;
}
int leftL=getHeight(root.left);
int rightL=getHeight(root.right);
//整体的平衡
if(Math.abs(leftL-rightL)<=1){
return true;
}
return false;
}
//求树高度的函数
public int getHeight(TreeNode root){
if(root==null){
return 0;
}
return Math.max(getHeight(root.left),getHeight(root.right))+1;
}
257. 二叉树的所有路径
给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。叶子节点 是指没有子节点的节点。
思路: 这边涉及到路径的问题,所以递归的参数中就需要携带之前走过的路径,不然最后的结果就只能是当前走过的一个节点而已,这边是着重需要考虑的问题
返回值 参数:返回一个String类型的集合,参数:二叉树,集合
终止条件:节点为空
单层循环:如果节点的左孩子节点不为空的话,加入路径,如果孩子节点不是叶子节点的话,继续往下,否则然后返回节点,如果右孩子不为空的话,加入路径,同样的思路,就是有一个回溯的概念,如果遇到了叶子节点,加入路径之后,需要回溯,同样,当左节点执行完了之后,回溯,然后执行右节点
写不出来,我好迷,List中的元素是String类型,怎么添加元素呢,直接加??,怎么往回走???
答案:
返回值 参数: 无返回值 参数:二叉树 路径(这个没想到) 结果集
终止条件:遇到叶子节点即表示路径到头了
单层循环:遍历左子树,回溯,遍历右子树,回溯
当运行到根节点的数据,遍历加入转换为String( 前期通过StringBuilder添加)
public List<String> binaryTreePaths(TreeNode root) {
List<String> res = new ArrayList<>();
if (root == null) {
return res;
}
List<Integer> paths = new ArrayList<>();
traversal(root, paths, res);
return res;
}
private void traversal(TreeNode root, List<Integer> paths, List<String> res) {
paths.add(root.val);
// 叶子结点
if (root.left == null && root.right == null) {
//paths.add(root.val);
// 输出
StringBuilder sb = new StringBuilder();
for (int i = 0; i < paths.size() - 1; i++) {
sb.append(paths.get(i)).append("->");
}
sb.append(paths.get(paths.size() - 1));
res.add(sb.toString());
return;
}
if (root.left != null) {
//paths.add(root.val);
traversal(root.left, paths, res);
paths.remove(paths.size() - 1);// 回溯
}
if (root.right != null) {
//paths.add(root.val);//如果直接放在里面的话,可能会存在树的根节点被添加多次的情况
traversal(root.right, paths, res);
paths.remove(paths.size() - 1);// 回溯
}
}
404. 左叶子之和
给定二叉树的根节点 root ,返回所有左叶子之和
思路:必须是叶子节点,必须是某个树的左节点
返回值 参数: 二叉树 变量(表示之前的左叶子和)
终止条件:遇到左叶子节点
单层循环:遍历左右子树
这样的思路不是对的,下面的代码在判断了一个左叶子节点之后就返回,是不对的
int count=0;
public int sumOfLeftLeaves(TreeNode root) {
if(root==null){
return 0;
}
count=sunOF(root,count);
return count;
}
public int sunOF(TreeNode node, int sum){
if(node.left!=null && node.left.left==null && node.left.right==null){
sum +=node.left.val;
return sum;
}
int lef=sunOF(node.left,sum);
int rig=sunOF(node.right,sum);
return lef+rig;
}
//这样的话,总是会出现某左叶子节点的重复添加
public int sumOfLeftLeaves(TreeNode root) {
if(root==null){
return 0;
}
int count=0;
count=sunOF(root,count);
return count;
}
public int sunOF(TreeNode node, int sum){
if(node.right!=null){
sum+=sunOF(node.right,sum);
}
if(node.left!=null){
if(node.left.left==null && node.left.right==null){
sum +=node.left.val;
}else{
sum+=sunOF(node.left,sum);
}
}
return sum;
}
答案:对于左叶子节点的判断是对的,但是递归写的有问题,分析了一下,大概率是我类比路径那题,把每次递归都要加上上一次的左叶子节点,就像路径一样,其实有些节点出现多次,不需要携带左叶子节点的值,左子树中左叶子节点的值+右子树中的左叶子的值+根节点的左孩子是左叶子节点的情况=左叶子节点和
public int sumOfLeftLeaves(TreeNode root) {
if (root == null) return 0;
int leftValue = sumOfLeftLeaves(root.left); // 左
int rightValue = sumOfLeftLeaves(root.right); // 右
int midValue = 0;
if (root.left != null && root.left.left == null && root.left.right == null) {
midValue = root.left.val;
}
int sum = midValue + leftValue + rightValue; // 中
return sum;
}
总结:路径之和以及左叶子节点的和感觉递归想的不太明白