代码随想录算法训练营day20|

文章介绍了四个关于二叉树的问题:如何构造最大二叉树,合并二叉树,搜索二叉搜索树以及验证二叉搜索树的有效性。关键在于理解二叉树的特性并利用递归有效地解决这些问题。对于最大二叉树,通过找到最大值作为根节点构建;合并二叉树时,节点值相加;搜索二叉搜索树时,利用其有序性;验证二叉搜索树时,需保证中序遍历结果递增。
摘要由CSDN通过智能技术生成

2023.4.3 最大二叉树

654. 最大二叉树 - 力扣(LeetCode)

思路类似于根据后序后中序数组构建二叉树。也是一个类似的过程。不同之处在于我们如何找到这个数组里面的最大值?

猜想:构建一个重复的数组,对其进行排序处理,然后将原来的数组放入哈希表中,这样我们就能根据排序后的数组来查找原数组中对应的最大元素了。

然而该猜想是错误的,因为对数组排序后会破坏其左右区间,无法判断最大值是在左子树还是右子树。

我们直接使用循环来找到最大值。

class Solution {
    public TreeNode constructMaximumBinaryTree(int[] nums) {
        return getRoot(nums,0,nums.length);
    }
    public TreeNode getRoot(int[] nums,int left,int right){
        //退出递归条件,同样使用左闭右开的区间,因此退出条件就是左区间大于等于右区间
        if(left >= right){
            return null;
        }
        //通过循环来确定最大值及其下标
        int maxIndex = -1;
        int maxValue = -1;
        for(int i = left;i<right;i++){
            if(maxValue < nums[i]){
                maxIndex = i;
                maxValue = nums[maxIndex];
            }
        }
        //确定好最大值后,我们就确定好了当前的根节点
        TreeNode root = new TreeNode(maxValue);
        //接下来要确定左子树的根节点与右子树的根节点
        //确定左子树的根节点,我们的做左区间变为了left到maxIndex之间,因为是左闭右开区间
        root.left = getRoot(nums,left,maxIndex);
        //确定右子树根节点,我们的右区间变为了maxIndex+1到right之间
        root.right = getRoot(nums,maxIndex + 1,right);
        //最后返回root
        return root;
    }
}

2023.4.3 合并二叉树

猜想:采用递归同时操作两个节点?

返回值 TreeNode ,传入参数 两个二叉树的根节点,结束条件,两个节点都为null,递归逻辑,如果都不为null,新节点就是两个节点值相加,有一个为null就只加一个的值,两个都为null直接返回null

class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        //这两个if语句已经包括了两者同时为null返回null的情况了
        if(root1 == null){
            return root2;
        }
        if(root2 == null){
            return root1;
        }
        root1.val += root2.val;
        root1.left = mergeTrees(root1.left,root2.left);
        root1.right = mergeTrees(root1.right,root2.right);
        return root1;
    }
}

2023.4.3 二叉搜索树中的搜索

700. 二叉搜索树中的搜索 - 力扣(LeetCode)

层序遍历?可以实现,效率太低了

class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            int length = queue.size();
            for(int i = 0;i<length;i++){
                TreeNode temp = queue.poll();
                if(temp.val == val){
                    return temp;
                }
                if(temp.left != null){
                    queue.offer(temp.left);
                }
                if(temp.right != null){
                    queue.offer(temp.right);
                }
            }  
        }
        return null;
    }
}

使用递归?

注意:二叉搜索树是一个有序的二叉树,它具有以下特点:

  • 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  • 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  • 它的左、右子树也分别为二叉搜索树

因此我们在搜索二叉搜索树时可以根据val值的大小进行有序的搜索。

class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
        if(root == null){
            return null;
        }
        if(root.val == val){
            return root;
        }
        TreeNode res = null;
        //二叉搜索树是有顺序的
        if(root.val > val){
            res = searchBST(root.left,val);
        }
        else if(root.val < val){
            res = searchBST(root.right,val);
        }
        return res;
    }
}

2023.4.3 验证二叉搜索树

98. 验证二叉搜索树 - 力扣(LeetCode)

验证一颗二叉树是否是二叉搜索树,我们首先要验证根节点与其左右子节点的关系,随后递归的验证其左右子节点与其子节点的关系。

很容易犯的错误代码:

原因,因为二叉搜索树的大小关系不仅仅是对左右两个子节点而言,而是对左右两个子树而言,它要求左子树上的所有节点严格小于根节点数值,右子树上的所有节点数值严格大于根节点数值。我们的代码仅仅检查了左右子节点与根节点的关系,没有考虑整体。

class Solution {
    public boolean isValidBST(TreeNode root) {
    if(root == null){//遍历到了叶子结点。
        return true;
    }
    if(root.left == null && root.right != null && root.val >= root.right.val){
         return false;
     }
     else if(root.left != null && root.right == null && root.val <= root.left.val){
         return false;
     }
     else if(root.left != null && root.right != null && (root.val <= root.left.val || root.val >= root.right.val)){
         return false;
     }
     return isValidBST(root.left) && isValidBST(root.left);
    }
}

实际上,我们可以使用中序遍历的方法,将得到的值计入数组中,我们只需要判断这个数组是否是一个递增的数组即可。

class Solution {
    List<Integer> res = new ArrayList<Integer>();
    //通过中序遍历将二叉树的值放入一个链表
    public void getList(TreeNode root){
    if(root == null){
        return;
    }
    getList(root.left);
    res.add(root.val);
    getList(root.right);
    }
    public boolean isValidBST(TreeNode root) {
        getList(root);
        int length = res.size();
        for(int i = 0;i<length-1;i++){
            if(res.get(i) >= res.get(i+1)){
                return false;
            }
        }
        return true;
    }
}

更进一步,我们不需要采用数组来储存结果,因为中序遍历的结果就是来判断该二叉树是否是递增的,我们只需要定义一个全局变量,在递归中序遍历时来判断其每个节点的值是否是依次递增的即可

class Solution {
    long max = Long.MIN_VALUE;
    //通过中序遍历来确定每个当前节点的数值都比上一个数值大。这个参考数值就是我们设定的max值,max值是动态更新的。
    public boolean isValidBST(TreeNode root) {
        if(root == null){
            return true;
        }
        if(!isValidBST(root.left)){
            return false;
        }
        if(root.val <= max){
            return false;
        }
        max = root.val;
        return isValidBST(root.right);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14天的训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15天的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16天的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值