树算法系列第二谈—— 二叉查找树与树的递归

二叉查找树与树的递归

引言

在上一篇文章中,主要介绍了二叉树的遍历相关以及相关联的算法这一篇也是系列的第二篇:二叉查找树相关的一些较为经典的力扣问题。在算法第四版中,对于树的介绍将其二叉查找树,与平衡查找树归于查询一章节中。对于平衡二叉树其查找的效率也是显而易见的,这里就不再过多展开。主要系列主线集中在对力扣的算法上面,具体的算法思想以及基础内容移步算法图书电子版。下面开始系列的问题的解决。

96-Unique Binary Search Trees

题目
给定一个值n,能构建出多少不同的值包含1…n的二叉搜索树(BST:就是对于一个节点来说,其左子树都会小于根节点,右子树都会大于根节点)?
例如给出n=3;有以下题解:
在这里插入图片描述
此时我们将其变换一个位置得到以下情况:
在这里插入图片描述

此时我们可以看到的是对于根节点是1的时候:等于其左子树的排列组合的个数与右子树排列组合的个数进行相乘,对于1来说,2,3都大于其,所以其右子树的排列组合为全零–也就是说只有一种情况,但是对于右边来说,右子树有2,3。但是对于2,3 来说此时又是分为两种情况,要么是2是根节点,要么3是根节点,所以最后规划来得到的是可以使用动态规划来进行题解:以此类推得到:当一个数组为1,2,3,……n时候,基于以下原则进行构建的BST树具有唯一性:以 i为根节点,其左子树由[1,i-1] 构成,右子树由[i+1,n] 构成
此时进行如下分析:

  • 如果数组是空的,也就是只能有一种的情况,所以 得到 f(0)=1;
  • 如果数组的元素只有一个时候,就是单节点情况,f(1)=1;
  • 如果有两个元素: 1,2 。就会有两种情况,所以可以得到:

f(2)=f(0) * f(1)+ f(1) * f(0)。1是根的情况与2是根的情况。

  • 此时若是有三个元素 1,2,3.
    f(3) =f(0) ∗ f(2) +f(1) ∗ f(1) +f(2) ∗ f(0)。表示的是为1为根,2为根,3为根的情况。于是我们可以根据以上的推敲得到以下公式:也推敲出可以是动态规划的思想来解决这道题目
    在这里插入图片描述

代码

public class Solution {
   
    public int numTrees(int n) {
   
         int [] f=new int[n+1];
        f[0]=1;
        f[1]=1;
        for(int i=2;i<=n;i++){
   
            for(int k=1;k<=i;k++){
   
                f[i]+=f[k-1]*f[i-k];
            }
        }
        return f[n];
    }
}

95-Unique Binary Search Trees-II

在这里插入图片描述
在完成了上一题的计算以后,我们知道了对于上一题的解放是,对于 1--n之间的某一个树来说 其左子树就是 1--i-1; 右子树是i+1--n 其中的i就是那个根。此时时候,将左右两边的相乘即可得到我们的个数,但是现在而言是当我们完成所有的输出思想还是相同的:
对于 i节点来说 我们使用递归来创建其左子树,然后递归创建右子树,最后将其左右子树在以i为根节点的左右子树上合并起来,就是我们要得到的数。
如下图完美诠释了我们的思路与思想。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iaZwpbht-1582783758083)(en-resource://database/1446:1)]
代码

import java.util.*;
public class Solution {
   
    public ArrayList<TreeNode> generateTrees(int n) {
   
        return unique(1,n);
    }
    private ArrayList<TreeNode> unique(int low,int high){
   
        ArrayList<TreeNode> array=new ArrayList<TreeNode>();
        // 在不能满足条件时候进行退出
        if(low>high){
   
            array.add(null);
            return array;
        }
        for(int i=low;i<=high;i++){
   
        // 构建左右子树
            ArrayList<TreeNode> left=unique(low,i-1);
            ArrayList<TreeNode> right=unique(i+1,high);
            for(int j=0;j<left.size();j++){
   
                for(int k=0;k<right.size();k++){
   
                   // 对左右子树进行合并
                   TreeNode root=new TreeNode(i);
                    root.left=left.get(j);
                    root.right=right.get(k);
                    array.add(root);
                }
            }
        }
        return array;
    }
}

98-Validate Binary Search Tree

在这里插入图片描述
思路: 在解决这道题目的时候想到的是对于任意的一棵树来说都是其左子树要小于根节点,然后右子树大于根节点,前面我们讲过,对于树类型的题目而言,使用栈的收益最高,然后特定的层序是使用队列实现。在特定的时候 例如使用到的循环每个小的部分使用递归也是可以做较好的实现。首先想到的是栈的实现,就是先,中,后序实现,但是我们发现,对于平衡二叉树来说,以上的三种方法遍历完成以后并没有特定的规律。然后使用到层序遍历,发现对于层序遍历来说,由于对于一棵树的左右子树来说,其在层序遍历的时候是完完全全邻接在一起的,这个时候就可以判断两两邻接的是不是递增即可。
然后考虑到的是递归来解决这类的问题,在下面的一个

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值