• 二叉树的构造默认如下:
/**
 * 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;
 *     }
 * }
 */

654. 最大二叉树

给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建:
创建一个根节点,其值为 nums 中的最大值。
递归地在最大值 左边 的 子数组前缀上 构建左子树。
递归地在最大值 右边 的 子数组后缀上 构建右子树。
返回 nums 构建的 最大二叉树 。

class Solution {
    public TreeNode constructMaximumBinaryTree(int[] nums) {
        TreeNode node = construct(nums, 0, nums.length);//本题数组区间为左闭右开
        return node;
    }

    TreeNode construct(int[] nums,int begin,int end){
        if(nums.length==1){
            return new TreeNode(nums[0]);//数组的长度为1,返回数组中的数构建的结点
        }
        //遍历数组,得到最大值的下标
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        int max = 0;
        for (int i = begin; i < end; i++) {
            map.put(nums[i], i);//数组中的值为key,下标为value
            max = Math.max(max,nums[i]);//找到数组中的最大值
        }
        int index = map.get(max);//数组中最大值的下标
        TreeNode node = new TreeNode(max);//构建结点
        if(index>begin){//如果左区间>=1
            node.left = construct(nums,begin,index);
        }
        if(index<end-1){//如果右区间>=1
            node.right = construct(nums,index+1,end);
        }
        return node;
    }
}
  • 还是构造二叉树的题目,但是比着昨天的两道要简单太多了,感觉自己也慢慢理解二叉树的递归构造

617. 合并二叉树

给你两棵二叉树: root1 和 root2 。
想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。
返回合并后的二叉树。
注意: 合并过程必须从两个树的根节点开始。

ψ(`∇´)ψ 我的思路

  • 前序遍历两棵树的所有结点(思路题目上写的很清楚了)
class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        TreeNode node;
        if (root1 == null && root2 == null) {
            return null;
        } else if (root1 == null && root2 != null) {
             node = root2;
        } else if (root2 == null && root1 != null) {
             node = root1;
        } else {
             node = new TreeNode(root1.val+ root2.val);
             node.left = mergeTrees(root1.left,root2.left);
             node.right = mergeTrees(root1.right,root2.right);
        }
        return node;
    }
}
  • 麻麻,我会递归喇😭

700. 二叉搜索树中的搜索

给定二叉搜索树(BST)的根节点 root 和一个整数值 val。
你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null 。

  • 考察BST的特性:当前结点左子树所有结点的值都小于当前结点,当前结点右子树所有结点的值都大于当前结点
class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
       if(root==null){
            return null;
        }
        if(root.val==val){
            return root;
        }
        else if(root.val>val){
            return searchBST(root.left,val);}
        else 
            return searchBST(root.right,val);
    }
}

时间复杂度O(n)

  • 今天的题写的特别顺欸,不知道是我进步了,还是题变简单了

98. 验证二叉搜索树

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
节点的左子树只包含 小于 当前节点的数。
节点的右子树只包含 大于 当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。

BST用中序遍历,结点值递增

class Solution {
    //中序遍历
   long max = Long.MIN_VALUE;//因为题目中最小结点的最小值是从Integer.MIN_VALUE开始的,要找比这个数还小的值,所以选了Long.MIN_VALUE
   public boolean isValidBST(TreeNode root) {
        if(root==null){return true;}//空结点既是二叉搜索树,又是平衡树,又是完全二叉树,又是满二叉树
        boolean left = isValidBST(root.left);//左
        if (root.val>max){//中
            max = root.val;//把当前值赋给max
        } else {
            return false;//当前结点的值小于等于上一个结点的值,不是BST
        }
        boolean right = isValidBST(root.right);//右
        return left && right;
    }
}
  • 代码还可以改进成双指针,这样就不用想着怎么找比结点的最小值还小的数了

530. 二叉搜索树的最小绝对差

ψ(`∇´)ψ 我的思路

  • 中序遍历得到递增的链表,遍历链表求两个相邻元素的差值,取最小
class Solution {
    public int getMinimumDifference(TreeNode root) {
        List<Integer> path = new ArrayList<>();
        inOrder(root,path);
        Integer[] nums = path.toArray(new Integer[0]);
        int fast=1;
        int slow =0;
        int min = Integer.MAX_VALUE;
        for (int i = 0; i < nums.length-1; i++) {
            min = Math.min(min,nums[fast]-nums[slow]);
            fast++;
            slow++;
        }
        return min;
    }

    void inOrder(TreeNode root, List<Integer> path){
        if(root.left!=null){
            inOrder(root.left,path);
        }
        path.add(root.val);
        if(root.right!=null){
            inOrder(root.right,path);
        }
    }
}

501. 二叉搜索树中的众数

给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。
如果树中有不止一个众数,可以按 任意顺序 返回。
假定 BST 满足如下定义:
结点左子树中所含节点的值 小于等于 当前节点的值
结点右子树中所含节点的值 大于等于 当前节点的值
左子树和右子树都是二叉搜索树

本题BST的定义发生改变:
结点左子树中所含节点的值 小于等于 当前节点的值
结点右子树中所含节点的值 大于等于 当前节点的值

  • ❗标记,标记,这题很好,双指针中序遍历BST,通过更新结果集的方式减少一次遍历
  • 下面是我听完视频后的第一次实现,把要用到的东西全加在了参数里,结果不行,参数一直在变。
class Solution {
    TreeNode pre;
    int count;
    public int[] findMode(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        int maxCount = 1;
        inOrder(root,count,maxCount,res);
        int[] result = new int[res.size()];
        for (int i = 0; i < result.length; i++) {
            result[i] = res.get(i);
        }
        return result;
    }

    // 中序遍历
    void inOrder(TreeNode cur,int count,int maxCount,List<Integer> res){
        if(cur==null){return;}
        if(cur.left!=null){inOrder(cur.left,count,maxCount,res);}//左
        if(pre == null){
            count = 1;//上一结点为空时,当前结点是第一个结点
        }
        else if (cur.val == pre.val){
            count++;//当前结点和上一结点的值相等,count++
        } else {
            count = 1;//当前结点和上一结点的值不等,count=1
        }
        if(count==maxCount){
            res.add(cur.val);//如果当前结点的次数=最大次数时,当前结点的值加入到结果集中
        }
        if(count>maxCount){
            //如果当前结点的count>最大次数
            maxCount = count;//更新maxCount
            res.clear();//清空res
            res.add(cur.val);
        }
        pre = cur;
        if(cur.right!=null){inOrder(cur.right,count,maxCount,res);}//右
    }
}
  • 把参数拿出来,测试通过
class Solution {
    int count;
    List<Integer> res = new ArrayList<>();
    TreeNode pre;
    int maxCount;
    public int[] findMode(TreeNode root) {
        inOrder(root);
        int[] result = new int[res.size()];
        for (int i = 0; i < result.length; i++) {
            result[i] = res.get(i);
        }
        return result;
    }

    // 中序遍历
    void inOrder(TreeNode cur){
        if(cur==null){return;}
        if(cur.left!=null){inOrder(cur.left);}//左
        if(pre == null){
            count = 1;//上一结点为空时,当前结点是第一个结点
        }
        else if (cur.val == pre.val){
            count++;//当前结点和上一结点的值相等,count++
        } else {
            count = 1;
        }
        if(count==maxCount){
            res.add(cur.val);//如果当前结点的次数=最大次数时,当前结点的值加入到结果集中
        }
        if(count>maxCount){
            //如果当前结点的count>最大次数
            maxCount = count;//更新maxCount
            res.clear();//清空res
            res.add(cur.val);
        }
        pre = cur;
        if(cur.right!=null){inOrder(cur.right);}//右
    }
}
  • 挺难的这题,卡我一天

236. 二叉树的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

所有 Node.val 互不相同 。
p != q
p 和 q 均存在于给定的二叉树中。

  • 要找最近的公共祖先,就要从下往上遍历,选择后序遍历。找到目标(p,q)就向上返回,如果当前结点的左右孩子都不空,就是结果,把结果再向上传递。

  • 有一种特例就是,一个目标结点a在另一个目标结点p里面,此时结果为p。这时我们只会找到一个目标结点p,当遇到结点p时就返回p,并不会再遍历到a。因为找不到另一个结点,p会被一直向上传递,最终返回。所以即使我们不再特殊处理这种情况,也对结果没有影响。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root==null){return null;}
        if(root==p||root==q){
            return root;//找到目标值解返回
        }
        TreeNode left = null;
        if(root.left!=null){
            left = lowestCommonAncestor(root.left, p, q);//左
        }
        TreeNode right = null;
        if(root.right!=null){
            right = lowestCommonAncestor(root.right, p, q);//右
        }
        //下面是中的逻辑
        if(left!=null&&right!=null){
            return root;//如果左右都有目标,返回当前结点
        } else if (left!=null&&right==null) {
            return left;//如果左孩子有目标值返回左孩子
        } else if (left==null&&right!=null) {
            return right;//如果右孩子有目标值返回右孩子
        } else {
            return null;//左右都没有找到目标,返回null
        }
    }
}

235. 二叉搜索树的最近公共祖先

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

  • 用上题的方法完全可解,但是BST有它自己的特性(如果当前结点的值在p,q之间,当前结点即为所求)
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root==null){return null;}
        if(root.val>p.val&&root.val>q.val){//如果当前结点的值大于p,q的值,就在当前左子树中寻找
            root = lowestCommonAncestor(root.left, p, q);
        } else if(root.val<p.val&&root.val<q.val){//如果当前结点的值小于p,q的值,就在当前右子树中寻找
            root = lowestCommonAncestor(root.right,p,q);
        } else if (root.val>p.val&&root.val<q.val) {//如果当前的结点值在p和q之间,当前结点即为所求
            return root;
        }
        return root;
    }
}

701. 二叉搜索树中的插入操作

给定二叉搜索树(BST)的根节点 root 和要插入树中的值 value ,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。
注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。

  • 思路还是比较清晰的,插入的值小于当前结点的时候,左子树空直接插,左子树不空调用递归插入左子树中。右边一样
class Solution {
    public TreeNode insertIntoBST(TreeNode root, int val) {
        if(root==null){return new TreeNode(val);}
        if(val< root.val){
            //要插入的值小于当前结点的值
            if(root.left==null){root.left = new TreeNode(val);}//结点的左子树为空,直接插入
            else {root.left = insertIntoBST(root.left,val);}//左子树不空,就在左子树里插入
        }
         else if (val> root.val) {
            //要插入的值大于当前结点的值
            if(root.right==null){root.right = new TreeNode(val);}//结点的右子树为空,直接插入
            else {root.right = insertIntoBST(root.right,val);}//就在右子树里插入
        }
        return root;
    }
}

450. 删除二叉搜索树中的节点

给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。

分以下5种情况:

  1. 要删除的结点在二叉树中不存在

  2. 要删除的结点存在于二叉树中:
    (1) 要删除的结点下没有孩子,直接返回null
    (2) 要删除的结点下只有左孩子,返回他的左孩子
    (3) 要删除的结点下只有右孩子,返回他的右孩子
    (4) 要删除的结点下有两个孩子,临时变量保存这两个孩子,右孩子继位并找右孩子的最左侧结点,把保存的左孩子挂在上面

class Solution {
    TreeNode temp1;
    TreeNode temp2;
    public TreeNode deleteNode(TreeNode root, int key) {
        if(root==null){return null;}
        if(root.val==key){//找到要删除的结点时
            if(root.left==null&&root.right==null){
                return null;//如果当前结点是叶子结点
            } else if (root.left!=null&&root.right==null) {
                return root.left;//当前结点只有左孩子,左孩子继位
            } else if (root.left==null&&root.right!=null) {
                return root.right;//当前结点只有右孩子,右孩子继位
            } else {
                //当前结点有两个孩子
                temp1 = root.left;//先把root的左孩子存起来
                temp2 = root.right;//把当前结点储存起来
                root = root.right;//让右孩子继位
                while (root.left!=null){root = root.left;}//找到右子树下最左侧的结点
                root.left = temp1;//把原来结点的左孩子挂在找到的结点下
                return temp2;
            }
        }
        if(key<root.val){
            //去左子树下删
            root.left = deleteNode(root.left, key);
        }
        if(key>root.val){
            //去右子树下删
            root.right = deleteNode(root.right, key);
        }
        return root;
    }
}

总结

  • 今天的题也很好,感觉可以慢慢理解二叉树的递归了,二叉树章节还剩三道题,留到周日再写,周日再回来补。

原文地址:https://www.cnblogs.com/xiannveryao/p/16783576.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性