111. 二叉树的最小深度
这题与求最大深度相似,依然是使用后序遍历,但是要注意,我们不能直接把最大深度中的max改为min直接提交这样是不对的。

如图,若直接改为min,那么返回的就是1,但实际上最小深度是到叶节点的最小距离,所以应该是3。代码如下:
class Solution {
public int minDepth(TreeNode root) {
return getHeight(root);
}
public int getHeight(TreeNode root){
if(root==null){
return 0;
}
int leftHeight=getHeight(root.left);
int rightHeight=getHeight(root.right);
if(root.left==null&&root.right!=null){
return 1+rightHeight;
}else if(root.left!=null&&root.right==null){
return 1+leftHeight;
}
int result=1+Math.min(leftHeight,rightHeight);
return result;
}
}
222. 完全二叉树的节点个数
这道题有两种方法,一种是按照普通树的思路,这种方法很简单,把左右子树的数量计算一下相加就行;另一种是完全二叉树的思路,我们需要对比,比如左子树的左侧和右侧深度是否相同,如果相同就是一个小的完全二叉树,完全二叉树的公式是2^深度-1,不相同就接着比较。但这种方法相对来说复杂一点,我这里只写了普通树的思路,代码如下:
class Solution {
public int countNodes(TreeNode root) {
return getNum(root);
}
public int getNum(TreeNode root){
if(root==null){
return 0;
}
int leftNum=getNum(root.left);
int rightNum=getNum(root.right);
int result=leftNum+rightNum+1;
return result;
}
}
110. 平衡二叉树
根据平衡二叉树的性质,我们把左右子树的高度相减即可,大于1的返回-1,代码如下:
class Solution {
public boolean isBalanced(TreeNode root) {
int a=getHeight(root);
if(a==-1){
return false;
}
return true;
}
public int getHeight(TreeNode node){
if(node==null){
return 0;
}
int leftHeigth=getHeight(node.left);
if(leftHeigth==-1){
return -1;
}
int rightHeight=getHeight(node.right);
if(rightHeight==-1){
return -1;
}
int result;
if(Math.abs(leftHeigth-rightHeight)>1){
result=-1;
}else{
result=1+Math.max(leftHeigth,rightHeight);
}
return result;
}
}
112. 路径总和
我们可以采用相减的办法,把目标值减去孩子的值,在叶子节点处且减为0时则返回true,代码如下:
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
return traversal(root,targetSum);
}
public boolean traversal(TreeNode node,int count){
if(node==null)
return false;
count-=node.val;
if(node.left==null&&node.right==null&&count==0){
return true;
}
if(node.left==null&&node.right==null&&count!=0){
return false;
}
if(node.left!=null){
if(traversal(node.left,count)==true){
return true;
}
}
if(node.right!=null){
if(traversal(node.right,count)==true){
return true;
}
}
return false;
}
}
首先在 hasPathSum 方法中调用递归函数 traversal,从根节点开始遍历整棵树,并把目标路径和 targetSum 传入。
递归函数 traversal(TreeNode node, int count) 的含义是:当前遍历到 node 节点时,还需要凑出的路径和为 count。函数首先判断当前节点是否为空,如果为空说明这条路径不存在,直接返回 false。
如果节点不为空,就执行 count -= node.val,表示当前节点已经被访问,因此从剩余目标值中减去当前节点的值,此时 count 表示从当前节点继续向下遍历还需要凑出的路径和。接着判断当前节点是否为叶子节点,如果当前节点既没有左孩子也没有右孩子,并且此时 count == 0,说明从根节点到该叶子节点的路径和正好等于 targetSum,函数返回 true;如果到达叶子节点但 count 不为 0,说明这条路径不满足条件,返回 false。
如果当前节点不是叶子节点,则继续递归遍历其子树,先判断左子树,如果左子树中存在满足条件的路径就直接返回 true;如果左子树没有找到,则继续判断右子树,如果右子树中存在满足条件的路径同样返回 true。当左右子树都没有找到满足条件的路径时,函数最终返回 false。
106. 从中序与后序遍历序列构造二叉树
这道题是一个中等难度的题,如何从中序遍历和后序遍历中得出二叉树呢?如下:
inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
中序遍历是:左中右,后序遍历是:左右中。由此我们可以得知,3是根节点,那么看前序遍历,以3为分界线,左边是左子树,右边是右子树。在后续遍历中:15,7,20可以得知20是中间的数,那么在前序遍历中,15在左,7在右。

我们写代码要分为以下几步:
1.前/后序数组长度为0,则字数为空
2.后序数组最后一个数为根节点
3.寻找根节点在前序数组中的位置,做切割
4.切割前序数组
5.切割中序数组
6.递归处理区间
代码如下:
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
return traversal(inorder,postorder);
}
public TreeNode traversal(int[] inorder,int[] postorder){
if(postorder.length==0){
return null;
}
int rootValue=postorder[postorder.length-1];
TreeNode root=new TreeNode(rootValue);
if(postorder.length==1){
return root;
}
int index=0;
for(index=0;index<inorder.length;index++){
if(inorder[index]==rootValue){
break;
}
}
int leftSize=index;
int[] leftInorder=new int[leftSize];
int[] rightInorder=new int[inorder.length-leftSize-1];
int[] leftPostorder=new int[leftSize];
int[] rightPostorder=new int[postorder.length-leftSize-1];
for(int i=0;i<leftSize;i++){
leftInorder[i]=inorder[i];
leftPostorder[i]=postorder[i];
}
for(int i=index+1;i<inorder.length;i++){
rightInorder[i-index-1]=inorder[i];
}
for (int i = leftSize; i < postorder.length - 1; i++) {
rightPostorder[i - leftSize] = postorder[i];
}
root.left=traversal(leftInorder,leftPostorder);
root.right=traversal(rightInorder,rightPostorder);
return root;
}
}
在 traversal 中,递归的终止条件是后序数组长度为 0,此时没有节点可构建,直接返回 null。接着,取后序数组的最后一个元素作为根节点值 rootValue,并创建一个 TreeNode 实例作为当前子树的根节点。如果后序数组长度为 1,说明当前子树只有根节点,直接返回即可。
然后,在中序数组中找到根节点的位置 index,这个位置把中序数组分为左子树和右子树两部分。左边长度为 leftSize = index,右边长度为 inorder.length - leftSize - 1。根据这个长度,分别创建左子树和右子树的中序数组 leftInorder、rightInorder 以及后序数组 leftPostorder、rightPostorder。
接下来,通过循环给左子树数组赋值:左子树的中序数组取中序数组前 leftSize 个元素,左子树后序数组取后序数组前 leftSize 个元素(不包含最后的根节点)。右子树的中序数组取中序数组从 index+1 到末尾的元素,右子树后序数组取后序数组从 leftSize 到倒数第二个元素(最后一个是根节点)。
最后,递归调用 traversal 构建左子树和右子树,并分别赋给 root.left 和 root.right,最终返回构建好的根节点。通过这种递归拆分和数组复制的方法,整个二叉树就可以按照原始中序和后序遍历序列重建出来。