对称二叉树
给你一个二叉树的根节点 root , 检查它是否轴对称。
class Solution {
public boolean isSymmetric(TreeNode root) {
if (root == null)
return true;
return compare(root.left, root.right);
}
public boolean compare(TreeNode left, TreeNode right) {
// 首先排除两个结点不满足情况
if (left == null && right != null)
return false;
else if (left != null && right == null)
return false;
else if (left == null && right == null)
return true;
else if (left.val != right.val)
return false;
// 此时就是开始递归子树了
boolean outside = compare(left.left, right.right);
boolean inside = compare(left.right, right.left);
return outside && inside;
}
}
该题方法挺多的,本次使用的是递归法,我们需要特别注意的是,对称不是所有结点的左右子节点都对称,而是根节点的左右子树对称,意思是我们需要比较两棵树的对称。
- 递归的起点是根节点的左右子节点,然后递归的结束条件就是有且只有一个结点为空(不对称),或者都不为空但是两个结点的值不一样(不对称),这两返回false;或者是两个结点都为null,此时就是对称的,返回true。
- 递归体:首先我们的左子树的左节点和右子树的右节点作比较,相同返回true,不同返回false;然后左子树的右节点和右子树的左节点作比较,相同返回true,不同返回false;当且仅当上面两个比较的返回值都为true时,该递归体里返回true。------ 这里需要理解的是,一旦有某个递归体返回了false,那么该递归体前面的都会false,结果false。
二叉树最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
class Solution {
public int maxDepth(TreeNode root) {
return getDepth(root);
}
public int getDepth(TreeNode root) {
if (root == null)
return 0;
int lhight = getDepth(root.left);
int rhight = getDepth(root.right);
return Math.max(lhight, rhight) + 1;
}
}
递归法,比较简单的一道题,通过看代码理解。
二叉树的最小深度
class Solution {
public int minDepth(TreeNode root) {
return getMinDepth(root);
}
public int getMinDepth(TreeNode root) {
if (root == null)
return 0;
int lhight = getMinDepth(root.left);
int rhight = getMinDepth(root.right);
if ( lhight == 0 || rhight == 0) {
return Math.max(lhight, rhight) + 1;
}
return Math.min(lhight, rhight) + 1;
}
}
最小深度和最大深度思路是差不多的,但是二叉树的特殊性,需要特殊考虑结点存在高度为0的子树。比如某节点。如果他的左子树为空,右子树高度为n,那么这棵子树的最小高度不能以0为标准,而需要以存在子树的部分为标准。------ 首先得有子树才能考虑子树的高度。
二叉树的所有路径
给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。
叶子节点 是指没有子节点的节点。
class Solution {
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;
}
public void traversal(TreeNode root, List<Integer> paths, List<String> res ) {
paths.add(root.val);
// 遇到叶子节点
if (root.left == null && root.right == null) {
StringBuffer sb = new StringBuffer();// 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) {
traversal(root.left, paths, res);
paths.remove(paths.size() - 1);
}
if (root.right != null) {
traversal(root.right, paths, res);
paths.remove(paths.size() - 1);
}
}
}
该题的定性是简单,但是我觉得还是挺难的,因为思路还是比较绕的,又涉及到了回溯、字符串拼接。
此题使用的方法主要还是递归法,因为需要路径,所以选择前序遍历。
该题的思路就是遇见叶子结点,就将路径中的元素拼成一个String放进res中,如果不是叶子节点就进去咯,但是进去后出来的时候需要删除该结点在paths中的路径,这就是回溯。
路径总和
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。
叶子节点 是指没有子节点的节点。
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if (root == null)
return false;
targetSum -= root.val;
if (root.left == null && root.right == null) {
return targetSum == 0;
}
if (root.left != null) {
boolean left = hasPathSum(root.left, targetSum);
if (left) {
return true;
}
}
if (root.right != null) {
boolean right = hasPathSum(root.right, targetSum);
if (right) {
return true;
}
}
return false;
}
}
该题和上一题的思路可以说是如出一辙,但是这个解法是换了一种表达方式。
这道题我们需要学习的是boolean变量在递归中怎么一步一步的传递 ----- 非常重要。
路径总和 II
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。
class Solution {
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
List<List<Integer>> res = new ArrayList<>();
if (root == null)
return res;
List<Integer> paths = new ArrayList<>();
Traversal(root, targetSum, res, paths);
return res;
}
public void Traversal(TreeNode cur, int targetSum, List<List<Integer>> res, List<Integer> paths) {
paths.add(cur.val);
if (cur.left == null && cur.right == null) {
// 找到了和为 targetsum 的路径
if (targetSum - cur.val == 0) {
res.add(new ArrayList<>(paths));
}
return ;
}
if (cur.left != null) {
Traversal(cur.left, targetSum - cur.val, res, paths);
paths.remove(paths.size() - 1);
}
if (cur.right != null) {
Traversal(cur.right, targetSum - cur.val, res, paths);
paths.remove(paths.size() - 1);
}
}
}
这道题比上面两道题与求所有路径和更像,但是奇怪的是,我们的targetSum 始终只能递减,直到为0停止,而不能使用sum = 0然后累加到targetSum 时来验证结果的正确性,这个我还是没有理解到为什么。
ArrayList的性质可以看一下,用数组挨着存储,取值是顺序取出,也就是可以根据索引取值。