#Java #二叉树
开源学习资料
Feeling and experiences:
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
题目要求的是每个节点,这样就想到了把问题分为多个子问题,利用递归来解。
注意:高度和深度的区别:
1. 高度(Height):
• 高度通常是指从一个节点到其最远叶子节点的最长路径上的边数。
• 在一个树结构中,树的高度通常是指根节点的高度,即从根节点到最远叶子节点的最长路径。
• 例如,在一棵二叉树中,根节点的高度是从根节点到最远叶子节点的边的数量。
2. 深度(Depth):
• 深度是指从根节点到一个特定节点的路径上的边数。
• 任何节点的深度都是从根节点到该节点的路径上的边的数量。
• 根节点的深度总是0,因为没有边连接根节点和它自己。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isBalanced(TreeNode root) {
return getHigh(root) != -1;
}
//获得节点高度
public int getHigh(TreeNode root){
if(root == null){
return 0;
}
//左右节点
int getLeft = getHigh(root.left);
int getRight = getHigh(root.right);
if(getLeft == -1 || getRight == -1 || Math.abs(getLeft - getRight)>1){
return -1;
}
//返回一个高度
return Math.max(getLeft, getRight) + 1;
}
}
练习多了就熟练了。
判断是否为平衡二叉树,肯定要先知道每个节点左右子树的高度差。
所以在主方法外,写了一个获取高度差的方法。
当左右子树高度之差绝对值大于1时,说明已经不平衡了,标记为-1,表示其不平衡。
只要出现了一个-1,说明这棵树是不平衡的,这个 -1 也会一直被返回给上一级,这样递归完,过程中只要出现了一个 -1,则结果必定为-1;
则最终结果返回false;
回顾复习一下层序遍历,用层序遍历解答:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isBalanced(TreeNode root) {
if(root == null){
return true;
}
int leftHigh = getHigh(root.left);
int rightHigh = getHigh(root.right);
return Math.abs(leftHigh - rightHigh)<=1 && isBalanced(root.left) && isBalanced(root.right);
}
//利用层序遍历获得高度
public int getHigh(TreeNode root){
if(root == null){
return 0;
}
Deque que = new LinkedList<>();
que.offer(root);
int deep =0;
while(!que.isEmpty()){
deep++;
int size = que.size();
for(int i =0;i
给你一个二叉树的根节点 root
,按 任意顺序 ,返回所有从根节点到叶子节点的路径。
叶子节点 是指没有子节点的节点。
这道题还用到了回溯:
关键就在于这条路走完了,返回到上一个节点继续执行
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
/**
* 递归法
*/
public List binaryTreePaths(TreeNode root) {
List res = new ArrayList<>();// 存最终的结果
if (root == null) {
return res;
}
List paths = new ArrayList<>();// 作为结果中的路径
traversal(root, paths, res);
return res;
}
private void traversal(TreeNode root, List paths, List res) {
paths.add(root.val);// 前序遍历,中
// 遇到叶子结点
if (root.left == null && root.right == null) {
// 输出
StringBuilder sb = new StringBuilder();
//把paths集合中的元素给sb
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) { // 左
traversal(root.left, paths, res);
paths.remove(paths.size() - 1);// 回溯
}
if (root.right != null) { // 右
traversal(root.right, paths, res);
paths.remove(paths.size() - 1);// 回溯
}
}
}
我认为,递归的本质就是栈,而栈本来就有回溯的性质。
而代码中的paths.remove(paths.size()-1); 作为回溯,其实就是为了跟递归保持一致,一个方法执行完了弹出,则结果的形式(paths存放的是路径)也要回到上一层。
更简单的写法:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List binaryTreePaths(TreeNode root) {
//用深度优先搜索
List paths = new ArrayList<>();
traversal(root,"",paths);
return paths;
}
public void traversal(TreeNode root,String path, List paths){
if(root != null){
StringBuffer pathSB = new StringBuffer(path);
pathSB.append(Integer.toString(root.val));
if(root.left == null && root.right == null){
paths.add(pathSB.toString());
}
else{
pathSB.append("->");
traversal(root.left,pathSB.toString(),paths);
traversal(root.right,pathSB.toString(),paths);
}
}
}
}
计算给定二叉树的所有左叶子之和。
这道题把条件理清楚就很简单
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int sumOfLeftLeaves(TreeNode root) {
if(root == null){
return 0;
}
return dfs(root);
}
public int dfs(TreeNode node){
//初始化sum
int sum =0;
//如果一个节点不为空,且是左节点,还是叶子节点
if(node.left != null){
sum += isLeafnode(node.left) ? node.left.val : dfs(node.left);
}
if(node.right != null && !isLeafnode(node.right)){
sum += dfs(node.right);
}
return sum;
}
//方法:判断是否是叶子节点
public boolean isLeafnode(TreeNode node){
return node.left == null && node.right == null;
}
}
另一种写法:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
int sum =0;
public int sumOfLeftLeaves(TreeNode root) {
dfs(root,false);
return sum;
}
public void dfs(TreeNode node,boolean isLeft){
if(node == null) return;
if(node.left == null && node.right == null && isLeft){
sum += node.val;
}
dfs(node.left,true);
dfs(node.right,false);
}
}
这种解法,把sum初始化为全局变量。
坦万虑以存诚,
憩遥情于八遐~
Fighting!