树 递归法 leetcode题目

二叉树的最大深度104

给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

 

1.必须从根节点开始,到叶子节点截至,返回最多节点数目(最长路径数+1)

2.后序遍历

 

public class 二叉树的最大深度 {
    //      Definition for a binary tree node.
    public int maxDepth(TreeNode root) {
        return getMaxDepth(root);
    }
    //后序遍历
    //返回每一级 最大深度
    private int getMaxDepth(TreeNode root){
        终止条件:当树为空时结束递归,并返回当前深度0
        if(root==null) return 0;
        //左右二选一 最大
        //递归改变:+1 包括根节点
         //root的左、右子树的最大深度
        int left=getMaxDepth(root.left);
        int right=getMaxDepth(root.right);
        //后序遍历:本级递归需要完成的任务
        return Math.max(left,right)+1;
    }
}
//迭代法
//使用 DFS 策略访问每个结点,同时在每次访问时更新最大深度。
//从包含根结点且相应深度为 1 的栈开始。然后我们继续迭代:将当前结点弹出栈并推入子结点。每一步都会更新深度。

 

二叉树的直径(两节点的最长路径)543

给定一棵二叉树,你需要计算它的直径长度。

一棵二叉树的直径长度是任意两个结点路径长度中的最大值

这条路径可能穿过也可能不穿过根结点

 

1.与104区别 :可能不经过根节点  所以使用了全局变量存放最大值;

2.类似 :104    1372 1367

3.后序遍历

 

//二叉树的最大直径  左子树+右子树
//找到一个节点 从该节点到左右两边叶子节点为止  两边边数和(经过的节点数-1)
public class 二叉树的直径 {
    //使用全局变量来维护最大值
    int max;//最长路径经过的节点个数   路径长度=节点个数-1
    public int diameterOfBinaryTree(TreeNode root) {
        max=1;
        getDepth(root);
        return max-1;//节点个数-1
    }
    //
    public int getDepth(TreeNode root){//以root为根节点的深度(左右中最大)
        //终止条件:访问到空节点 null时 返回深度为0
        if(root==null) return 0;//终止
        //左子树深度
        int leftDia=getDepth(root.left);//递归 左子树
        //右子树深度
        int rightDia=getDepth(root.right);//递归 右子树
        //后序遍历
        //本轮所需要做的事:
 
        //与104 二叉树最大深度差异点:更新“根节点” 更新最大深度
        max=Math.max(leftDia+rightDia+1,max);// 计算当前根节点的深度,即L+R+1 并更新 完整整个树中最大的(最大深度)
        //返回当前节点的最大深度
        return Math.max(leftDia,rightDia)+1;//返回该节点为根的子树的深度
    }
}

最长同值路径687

给定一个二叉树,找到最长的路径,这个路径中的每个节点具有相同值。 这条路径可以经过也可以不经过根节点。

注意:两个节点之间的路径长度由它们之间的边数表示。

 

1.起始不一定是根节点,求最大 全局变量维护

2.访问节点的值  条件:同值 连接

3.后序遍历

 

public class 最长同值路径 {
    //可以不经过根节点,即“根节点”可以改变
    //求所有情况最大值
    //全局变量维护更新
    int max;
    public int longestUnivaluePath(TreeNode root) {
        //
        max=0;
        if(root==null) return 0;
        getMaxPath(root);
        return max;
    }
    //最长同值路径:返回单侧最长路径(包含root)在内;
    //以node为根(不考虑父节点,父节点在不在最长路径中是父节点管的事)且包含node.val值本身所在的**单侧**“最长“同值路径的长度
    //条件 :同值 连接
    public int getMaxPath(TreeNode root){
        //递归终止条件:访问到空节点 
        if(root==null) return 0;
        //获取左右子树的最大深度
        int left=getMaxPath(root.left);
        int right=getMaxPath(root.right);
        //单次递归需要做的事:
        int leftSum=0,rightSum=0;
        //防止空指针异常
        //存在左子节点且左子节点的值与当前根节点的值相同
        if(root.left!=null&&root.left.val==root.val)
            leftSum=left;
        //存在右子节点且右子节点的值与当前根节点的值相同
        if(root.right!=null&&root.right.val==root.val)
            rightSum=right;
        //维护更新最大值
        max=Math.max(max,leftSum+rightSum);
        //返回当前根节点的最大深度
        return Math.max(leftSum,rightSum)+1;
    }
}

二叉树中的最大路径和124

给定一个非空二叉树,返回其最大路径和。

本题中,路径被定义为一条从树中任意节点出发,达到任意节点的序列。

该路径至少包含一个节点,且不一定经过根节点。

 

1.后序遍历

2.

 

public class 二叉树中的最大路径和 {
    //全局变量 存放更新最大路径和
    int maxSum=Integer.MIN_VALUE;//由于节点值和可能出现负的,此时不能设置初始值为0,设为最小整数
    public int maxPathSum(TreeNode root) {
        if(root==null) return 0;
        getMaxSum(root);
        // maxPathSum(root.left);
        // maxPathSum(root.right);
        return maxSum;
    }
    private int getMaxSum(TreeNode root){
        //递归终止条件:访问到空节点,返回:所经过的节点值的和为0
        if(root==null) return 0;
        // if(root.left==null&&root.right==null) return 0;叶子节点应该返回叶子节点的值,此行错误
        //左右子树的节点值的和
        //有可能和为负数,此时舍弃该子树 和用0取代
        int left=Math.max(getMaxSum(root.left),0);
        int right=Math.max(getMaxSum(root.right),0);
        //本次递归所需要做的事情:
        //1.更新最大值
        maxSum=Math.max(root.val+left+right,maxSum);
        //返回 根节点在内,单侧 最大 节点值的和
        int sum=root.val+Math.max(left,right);
        return sum;
    }
}

 

平衡二叉树110

给定一个二叉树​,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:

一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。

 

1.从根节点开始 到 叶子节点 截止  求高度 (返回节点数) 返回是否平衡

2.后序遍历

 

/**
 * 后序遍历
 * 判断left子树和right子树是否是平衡二叉树,如果不是则直接返回false。
 * 再判断两树高度差是否不大于1,如果大于1也直接返回false。
 * 否则说明以root为节点的子树是平衡二叉树,返回高度
 */
public class 平衡二叉树 {
    public boolean isBalanced(TreeNode root) {
        return height(root)!=-1;
    }
    //对于一颗树,它是一个平衡二叉树需要满足三个条件:
    //它的左子树是平衡二叉树;
    //它的右子树是平衡二叉树;
    //它的左右子树的高度差不大于1。
    private int  height(TreeNode root){
        //递归终止条件:没有节点了,高度为0
        if(root==null) return 0;
        //本轮所需要做的:
        //不平衡的情况有3种:左树不平衡、右树不平衡、左树和右树差的绝对值大于1
        int leftHeight=height(root.left);
        //左树不平衡
        if(leftHeight==-1) return -1;
        int rightHeight=height(root.right);
        //右树不平衡
        if(rightHeight==-1) return -1;
        //左树和右树差的绝对值大于1
        if(Math.abs(leftHeight-rightHeight)>=2)
            return -1;
        //返回值:左右子树最高高度+1: 即本节点所在的树的高度
        return Math.max(leftHeight,rightHeight)+1;
    }
}

二叉树中的最长交错路径1372

给你一棵以 root 为根的二叉树,二叉树中的交错路径定义如下:

    选择二叉树中 任意 节点和一个方向(左或者右)。

    如果前进方向为右,那么移动到当前节点的的右子节点,否则移动到它的左子节点。

    改变前进方向:左变右或者右变左。

    重复第二步和第三步,直到你在树中无法继续移动。

交错路径的长度定义为:访问过的节点数目 - 1(单个节点的路径长度为 0 )。

请你返回给定树中最长 交错路径 的长度。

 

 

 

1.类似于

2.多一个变量,记录当前方向

 

public class 二叉树中的最长交错路径 {
    //任意节点 不一定是根节点开始
    //全局存储维护更新最大路径
    //左变右 右变左  初始二选一  每步记录当前应该走的方向
    //记录当前走过的路径
    int max;
    public int longestZigZag(TreeNode root) {
        max=0;
        longestZigZag(root,true);
        // longestZigZag(root, false);加不加都正确,不过加了速度7ms变8ms
        return max;
    }
    public int longestZigZag(TreeNode root,boolean isLeft) {
        //递归终止条件:访问空节点,最长路径为0
        if(root==null) return 0;
        //下面的叶子节点操作不需要
//        if(root.left==null && root.right==null) return 1;
        int left=0,right=0;
        //下面不需要判断,判断会出错
        // if(isLeft){//左
        right=longestZigZag(root.right,false);
        left=longestZigZag(root.left,true);
        // }else{
        //     right=longestZigZag(root.right,true);
        //     left=longestZigZag(root.left,false);
        // }
        //本次递归所需要做的事:
        //更新   当前根节点最大路径(左右子树路径长度较大者)
        // 更新总体最大路径
        int depth=Math.max(left,right);
        max=Math.max(max,depth);
        //当前节点的方向为向左,意味着上一步为向右,返回右子树的路径长度+1
        return isLeft?right+1:left+1;//重要
    }
}
/*class Solution {
    int sum=0;
    public:
    void longest(TreeNode* root, int flag, int val)
    {
        if (!root) return ;
        sum=max(sum,val);
        if (flag)
        {
            longest(root->left, !flag, val+1);
            longest(root->right, flag, 1);//重新置1
        }
        else
        {
            longest(root->right, !flag, val+1);
            longest(root->left, flag, 1);
        }
    }
    int longestZigZag(TreeNode* root) {
        if (!root) return 0;
        longest(root,true,0);
        longest(root,false,0);
        return sum;
    }
};*/

路径总和112判断路径和是否等于一个数

给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。

说明: 叶子节点是指没有子节点的节点。

 

1.必须 从 根节点 到 叶子节点

2.前序遍历

 

public class 路径总和 {
    public boolean hasPathSum(TreeNode root, int sum) {
        //递归终止条件:访问到空节点
        if(root==null) return false;
        // 从根到叶子节点遍历
        //通过减数 判断最后是否能为0
        //前序遍历
        //本次递归需要做的事情
        //1.减去本节点的值
        //2.判断本节点是否为叶子节点
        //3.判断是否已经减到0
        sum-=root.val;
        // if(sum==0) return true;//不能直接判断,无法确保本节点为叶子节点
        if(root.left==null&&root.right==null){//判断到达叶子节点
            return sum==0;//判断是否减到0
        }
        //没有减到0
        //进一步判断:左子树和右子树是否存在符合条件的路径
        boolean left=hasPathSum(root.left,sum);
        boolean right=hasPathSum(root.right,sum);
        return left||right;
    }
}

路径总和437统计路径和等于一个数的路径数量

给定一个二叉树,它的每个结点都存放着一个整数值。

找出路径和等于给定数值的路径总数。

路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。

二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。

 

1.区别于上一题:不一定从 根节点开始,不一定 到 叶子节点结束

2.全局变量

3.双重递归 思路:首先先序递归遍历每个节点,再以每个节点作为起始点递归寻找满足条件的路径。存在大量重复计算

 

public class 路径总和3 {
    public int pathSum(TreeNode root, int sum) {
        if(root==null) return 0;
        int res=getPathSum(root,sum);
        int left=pathSum(root.left,sum);
        int right=pathSum(root.right,sum);
        return res+left+right;
    }
    private int getPathSum(TreeNode root, int sum){
        //递归终止条件
        if(root==null) return 0;
        //本轮递归所需要做的事
        sum-=root.val;
        int res=sum==0?1:0;
        //返回当前根节点的路径和
        return res+getPathSum(root.left,sum)+getPathSum(root.right,sum);
    }
    // int count;
    // public int pathSum(TreeNode root, int sum) {
    //     if(root==null) return 0;
    //     getPathSum(root,sum);
    //     pathSum(root.left,sum);
    //     pathSum(root.right,sum);
    //     return count;
    // }
    // private void getPathSum(TreeNode root, int sum){
    //     if(root==null) return;
    //     sum-=root.val;
    //     if(sum==0){
    //         count++;
    //         // return count;
    //     }
    //     getPathSum(root.left, sum);
    //     getPathSum(root.right, sum);
    //     // return count;
    // }
}

 

//优化
/*
所以第二种做法,采取了类似于数组的前n项和的思路,比如sum[4] == sum[1],那么1到4之间的和肯定为0
对于树的话,采取DFS加回溯,每次访问到一个节点,把该节点加入到当前的pathSum中
然后判断是否存在一个之前的前n项和,其值等于pathSum与sum之差
如果有,就说明现在的前n项和,减去之前的前n项和,等于sum,那么也就是说,这两个点之间的路径和,就是sum
最后要注意的是,记得回溯,把路径和弹出去
作者:a380922457
链接:https://leetcode-cn.com/problems/path-sum-iii/solution/liang-chong-fang-fa-jian-dan-yi-dong-ban-ben-by-a3/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
*/
class Solution {
    public int pathSum(TreeNode root, int sum) {
        HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
        map.put(0, 1);
        return helper(root, map, sum, 0);
    }
 
    int helper(TreeNode root, HashMap<Integer, Integer> map, int sum, int pathSum){
        int res = 0;
        if(root == null) return 0;
 
        pathSum += root.val;
        res += map.getOrDefault(pathSum - sum, 0);
        map.put(pathSum, map.getOrDefault(pathSum, 0) + 1);
        res = helper(root.left, map, sum, pathSum) + helper(root.right, map, sum, pathSum) + res;
        map.put(pathSum, map.get(pathSum) - 1);
        return res;
    }
}
//另一个回溯
/*
作者:ustcyyw
链接:https://leetcode-cn.com/problems/path-sum-iii/solution/437java-hui-su-da-bai-100-by-ustcyyw/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
*/
    private int count;
    public int pathSum(TreeNode root, int sum) {
        count = 0;
        backTrack(root, sum, new int[1000], 0);
        return count;
    }
    public void backTrack(TreeNode x, int sum, int[] pathItem, int curIndex){
        if(x == null) return;
        if(x.val == sum) count++;
        for(int i = curIndex - 1, temp = x.val; i >= 0; i--){
            temp += pathItem[i];
            if(temp == sum)
                count++;
        }
        pathItem[curIndex] = x.val;
        backTrack(x.left, sum, pathItem, curIndex + 1);
        backTrack(x.right, sum, pathItem, curIndex + 1);
    }

二叉树的最小深度111

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

说明: 叶子节点是指没有子节点的节点。

 

 

1.根 到 叶子

 

//和最大相反
/*
public int maxDepth(TreeNode root) {
    if (root == null) {
        return 0;
    }
    return 1+Math.max(maxDepth(root.left), maxDepth(root.right));
}
*/
/*
求最小深度时将Math.max换成Math.min即可,
但要注意如果根节点的左或右子树为空的话是构不成子树的。
而最小深度是要求从根节点到子树的。
当左或右子树为空时,不符合要求。
*/
/*
public int minDepth(TreeNode root) {
    if (root == null) {
        return 0;
    }
    // null节点不参与比较
    if (root.left == null && root.right != null) {
        return 1 + minDepth(root.right);
    }
    // null节点不参与比较
    if (root.right == null && root.left != null) {
        return 1 + minDepth(root.left);
    }
    return 1 + Math.min(minDepth(root.left), minDepth(root.right));
}
*/
public class 二叉树的最小深度 {
    public int minDepth(TreeNode root) {
        if(root==null) return 0;
        return getMinDepth(root);
    }
    public int getMinDepth(TreeNode root){
        //递归终止条件:访问到空节点
        if(root==null) return 0;
        if(root.left==null&&root.right==null) return 1;
        if(root.left!=null&&root.right!=null){
            int left=getMinDepth(root.left);
            int right=getMinDepth(root.right);
            return Math.min(left,right)+1;
        }
        if(root.left!=null){
            return getMinDepth(root.left)+1;
        }
        if(root.right!=null){
            return getMinDepth(root.right)+1;
        }
        return 0;
    }
}

 

 

二叉树中的列表1367

给你一棵以 root 为根的二叉树和一个 head 为第一个节点的链表。

如果在二叉树中,存在一条一直向下的路径,且每个点的数值恰好一一对应以 head 为首的链表中每个节点的值,那么请你返回 True ,否则返回 False 。

一直向下的路径的意思是:从树中某个节点开始,一直连续向下的路径。

 

 

 

1.起始不一定是 根节点

 

 

public class 二叉树中的列表 {
    public boolean isSubPath(ListNode head, TreeNode root) {
        // return dfs(head,root);//考虑不是必须从根节点开始
        if(head==null) return true;//空链表 匹配
        //因为下面要访问root的左右子树
        //为了避免空指针
        //添加判断root是否为空
        if(root==null) return false;
        // return dfs(head,root)||dfs(head,root.left)||dfs(head,root.right);
        //重要:后面两个等于是换起始根节点(先往左子树dfs判断,再往右)
        return dfs(head,root)||isSubPath(head,root.left)||isSubPath(head,root.right);
    }
    //以root为根节点的树与链表匹配的关键条件:
    //1.当前root值与head值相等;2.左子树匹配3.右子树匹配
    private boolean dfs(ListNode head, TreeNode root){
        //递归终止条件:
        //访问到链表的空节点 说明匹配成功
        if(head==null) return true;//空链表 匹配
        //访问到树的空节点  说明不匹配
        if(root==null) return false;//空节点 不匹配
        //本次递归需要做的事情:
        //前序遍历
        //当前树节点的值 与 当前链表节点的值 不等 ,返回不符合
        if(head.val!=root.val) return false;
        //判断
        boolean left=dfs(head.next,root.left);
        boolean right=dfs(head.next,root.right);
        // if(head.next==null) return
        //前面当前值已经相等,返回左右子树是否都匹配
        return left||right;
    }
}

 

检查子树 面试04.10

检查子树。你有两棵非常大的二叉树:T1,有几万个节点;T2,有几万个节点。设计一个算法,判断 T2 是否为 T1 的子树。

如果 T1 有这么一个节点 n,其子树与 T2 一模一样,则 T2 为 T1 的子树,也就是说,从节点 n 处把树砍断,得到的树与 T2 完全相同。

 

 

1.从上一题1367 -----链表改树,完全一致

 

class 检查子树 {
    public boolean checkSubTree(TreeNode t1, TreeNode t2) {
        if(t2==null) return true;
        if(t1==null) return false;
        return check(t1,t2)||checkSubTree(t1.left,t2)||checkSubTree(t1.right,t2);
    }
    private boolean check(TreeNode t1, TreeNode t2){
        if(t2==null) return true;
        if(t1==null) return false;
        if(t2.val!=t1.val) return false;
        return check(t1.left,t2.left)||check(t1.right,t2.right);
    }
}

另一个树的子树572

给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树。

s 的一个子树包括 s 的一个节点和这个节点的所有子孙。

s 也可以看做它自身的一棵子树。

 

 

1.和前两题有边界差异

 

class 另一个树的子树 {
    public boolean isSubtree(TreeNode s, TreeNode t) {
        // if(t==null) return true;
        // if(s==null) return false;
        if (t == null || s == null) return false;
        return isSub(s,t)||isSubtree(s.left,t)||isSubtree(s.right,t);  
    }
    private boolean isSub(TreeNode s, TreeNode t){
        //注释的边界错误
        // if(t==null) return true;
        // if(s==null) return false;
        if (t == null && s == null) return true;
        if (t == null || s == null) return false;
        if(s.val!=t.val) return false;
        boolean left=isSub(s.left,t.left);
        boolean right=isSub(s.right,t.right);
        return left&&right;
    }
}

翻转二叉树226

 

 

public class 翻转二叉树 {
    public TreeNode invertTree(TreeNode root) {
        //递归终止条件 空节点
        if(root==null) return null;
        //前序遍历
        //翻转后的左右子树
        TreeNode left=invertTree(root.left);
        TreeNode right=invertTree(root.right);
        //本轮递归操作
        //1.根节点左节点换为原来的右子树
        root.left=right;
        //2.根节点右节点换为原来的左子树
        root.right=left;
        //返回根节点
        return root;
    }
}

合并二叉树617

给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。

你需要将他们合并为一个新的二叉树。

合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值

否则不为 NULL 的节点将直接作为新二叉树的节点。

 

public class 合并二叉树 {
    public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
        //递归终止条件
        if(t1==null) return t2;
        if(t2==null) return t1;
        //返回合并后的左右子树
        TreeNode left=mergeTrees(t1.left,t2.left);
        TreeNode right=mergeTrees(t1.right,t2.right);
        //本次递归操作
        //根节点值更新为 求和
        TreeNode root=new TreeNode(t1.val+t2.val);
        //将左右子树分别接到根节点
        root.left=left;
        root.right=right;
        // t1.left.val+=t2.left.val;
        // t1.right.val+=t2.left.val;
        return root;
    }
}

 

对称二叉树101

 

 

//递归
public class 对称二叉树 {
    public boolean isSymmetric(TreeNode root) {
        if(root==null) return true;
        boolean res=isSymmetric(root,root);
        return res;
    }
    private boolean isSymmetric(TreeNode leftNode,TreeNode rightNode){
        //递归终止:同时遍历到空节点 对称
        if(leftNode==null&&rightNode==null) return true;
        //只有一个遍历到了空 不对称
        if(leftNode==null||rightNode==null) return false;
        //本地递归操作:
        //判断当前节点左右子节点值相等 且左右子树对称
        return leftNode.val==rightNode.val&&isSymmetric(leftNode.left,rightNode.right)&&isSymmetric(leftNode.right,rightNode.left);
    }
}
//迭代
class Solution {
    public boolean isSymmetric(TreeNode root) {
        return check(root,root);
    }
    private boolean check(TreeNode leftNode,TreeNode rightNode){
        Queue<TreeNode> que=new LinkedList<>();
        que.offer(leftNode);
        que.offer(rightNode);
        while(!que.isEmpty()){
            leftNode=que.poll();
            rightNode=que.poll();
            if(leftNode==null&&rightNode==null) return true;
            if(leftNode==null||rightNode==null||leftNode.val!=rightNode.val) return false;
            que.offer(leftNode.left);
            que.offer(rightNode.right);
            que.offer(leftNode.right);
            que.offer(rightNode.left);
        }
        return true;
    }
}

左叶子之和404

 

 

class 左叶子之和 {
    public int sumOfLeftLeaves(TreeNode root) {
        if(root == null) return 0;
        int res = 0;
        //判断节点是否是左叶子节点,如果是则将它的和累计起来
        if(root.left != null && root.left.left == null && root.left.right == null){
            res += root.left.val;//res = root.left.val;
        }
        return sumOfLeftLeaves(root.left) + sumOfLeftLeaves(root.right) + res;
    }
}
/*public int sumOfLeftLeaves(TreeNode root) {
        if(root==null) return 0;
        return sumOfLeftLeaves(root.left,true)+sumOfLeftLeaves(root.right,false);
    }
    public int sumOfLeftLeaves(TreeNode root,boolean isLeftLeaves){
        //递归终止条件:空节点 和为0
        if(root==null) return 0;
        int leaves=0;
        //判断为左叶子
        if(isLeftLeaves&&root.left==null&&root.right==null){//只判断了叶子节点,没判断左叶子
            leaves=root.val;
        };
        //左右子树的左叶子之和
        int left=sumOfLeftLeaves(root.left,true);//
        int right=sumOfLeftLeaves(root.right,false);
        return leaves+left+right;
    }*/

 

最大二叉树654

给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下:

    二叉树的根是数组中的最大元素。

    左子树是通过数组中最大值左边部分构造出的最大二叉树。

    右子树是通过数组中最大值右边部分构造出的最大二叉树。

通过给定的数组构建最大二叉树,并且输出这个树的根节点。

 

public class 最大二叉树 {
    public TreeNode constructMaximumBinaryTree(int[] nums) {
        if(nums==null||nums.length==0)
            return null;
        //递归终止条件
        //nums中数字都取了以后
        TreeNode root=constructMaximum(nums,0,nums.length-1);
        return root;
    }
    public int findMax(int[] nums,int i,int j){
        // int index=i;
        int max=nums[i],index=i;
        for(int t=i;t<=j;t++){
            if(nums[t]>max){
                index=t;
                max=nums[t];
            }
        }
        return index;//返回[i,j]之间最大值的索引
    }
    public TreeNode constructMaximum(int[] nums,int i,int j) {
        // if(nums==null||nums.length==0)
        //     return null;
        //递归终止条件
        if(i>j) return null;
        //nums中数字都取了以后
//        int i=0,j=nums.length-1;
        int mid=findMax(nums,i,j);
        TreeNode root=new TreeNode(nums[mid]);
        // TreeNode left=null,right=null;错误
        //左子树最大值
        //可以不判断mid左右边是否有数
        //第一步边界判断了 i>j则返回null
        root.left=constructMaximum(nums,i,mid-1);//左边界不变 不可以设为0
        root.right=constructMaximum(nums,mid+1,j);//右边界不变 不可以设为最后一个
//        if(mid>0){
//            root.left=constructMaximum(nums,i,mid-1);
//        }
//        if(mid<nums.length-1){
//            root.right=constructMaximum(nums,mid+1,j);
//        }
        // root.left=left;错误
        // root.right=right;错误
        return root;
    }
}

二叉树中第二小的节点671

给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 2 或 0。

如果一个节点有两个子节点的话,那么该节点的值等于两个子节点中较小的一个。

给出这样的一个二叉树,你需要输出所有节点中的第二小的值。如果第二小的值不存在的话,输出 -1 。

 

public int findSecondMinimumValue(TreeNode root) {
        return myfun(root, root.val);
    }
    public int myfun(TreeNode root, int val) {
        if (root == null) {
            return -1;
        }
        if (root.val > val) {
            return root.val;
        }
        int l = myfun(root.left, val);
        int r = myfun(root.right, val);
        if (l > val && r > val) {
            return Math.min(l,r);
        }
        return Math.max(l,r);
    }
//方法2
public class 二叉树中第二小的节点 {
    public int findSecondMinimumValue(TreeNode root) {
        //一个节点要么具有 0 个或 2 个子节点,如果有子节点,那么根节点是最小的节点。
        //递归终止条件:空节点 返回-1
        if (root == null) return -1;
        //只有一个节点 叶子节点 返回-1
        if (root.left == null && root.right == null) return -1;
        //存在两个叶子节点
        //本次递归需要做的事:
        int leftVal = root.left.val;
        int rightVal = root.right.val;
        //左节点较小 右节点比根节点大 ----找左子树第二小
        if (leftVal == root.val) leftVal = findSecondMinimumValue(root.left);
        //右节点较小 左节点比根节点大 ----找右子树第二小
        if (rightVal == root.val) rightVal = findSecondMinimumValue(root.right);
        //左子树右子树均存在 返回两者最小
        if (leftVal != -1 && rightVal != -1) return Math.min(leftVal, rightVal);
        //只有左子树存在 返回左边
        if (leftVal != -1) return leftVal;
        //只有右子树存在 返回右边
        return rightVal;
    }
}

打家劫舍3 337

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值