二叉树 — 返回最大的二叉搜索子树大小

题目:
给定一棵二叉树的head节点,返回这颗二叉树中最大的二叉搜索子树的大小。
一颗二叉树来讲,可能整棵树不是搜索二叉树,但子树是一颗搜索二叉树。如下图所示,这时要返回这颗子搜索二叉树的最大节点个数。下图中,最大的二叉搜索子树大小为:3(5 -> 1 -> 7)。
在这里插入图片描述
子树的概念是:每个单独节点算一棵子树, 5 -> 1 -> 7三个节点算一棵子树(不可以舍弃任何一个)
1 -> 5 -> 7 -> 6 -> 2同样也算一棵子树,同样不可以舍弃任何一个节点。

递归方式

  1. 只有左树满足二叉搜索树的情况
  2. 只有右树满足二叉搜索树的情况
  3. 整棵树都是二叉搜索树的情况
  4. 判断是否是二叉搜索树需要左右子树max、min的值和当前值节点值进行比较,如果左树最大值小于当前值,右树最小值大于当前值,则说明是一颗二叉搜索树
  5. 需要整棵树的节点数变量(allSize)和满足子树最大二叉搜索树节点数变量(maxBSTSubtreeSize),如果两个值相等,说明是二叉搜索树,如果不相等,则说明不是(用这两个值在构建Info信息类时,可省略一个bollean isBST的变量)。
  6. 根据4、5的要求构建Info对象,递归调用并收集左右子节点的Info信息进行判断。

代码:
Info类用于收集树的信息,并通过递归返回给上层,供上层调用进行分析。

public static class Info{
        int max;
        int min;
        int allSize;
        //满足子树是二叉搜索树最大节点个数
        int maxBSTSubtreeSize;

        public Info(int maxBSTSubtreeSize,int allSize,int max,int min){
            this.maxBSTSubtreeSize = maxBSTSubtreeSize;
            this.allSize = allSize;
            this.max = max;
            this.min = min;
        }
    }
public static int largestBSTSubtree(Node head){
        if(head == null){
            return 0;
        }

        return process(head).maxBSTSubtreeSize;
    }

     //       6
    //    2      7
    // 1    5
    public static Info process(Node head){
        //如果节点为null,不方便构建Info对象信息,所以返回null,下面要对Info对象进行非null判断。
        if (head == null){
            return null;
        }

        Info leftInfo = process(head.left);
        Info rightInfo = process(head.right);

        int max = head.val;
        int min = head.val;
        int allSize = 1;

        if (leftInfo != null){
            max = Math.max(max,leftInfo.max);
            min = Math.min(min,leftInfo.min);
            allSize += leftInfo.allSize;
        }

        if (rightInfo != null){
            max = Math.max(max,rightInfo.max);
            min = Math.min(min,rightInfo.min);
            allSize += rightInfo.allSize;
        }
        //p为每棵树的满足二叉搜索树的节点个数。
        
        //如果左子树不为null,则修改 p1 为 左子树的最大二叉搜索树的个数
        int p1 = -1;
        if (leftInfo != null){
            p1 = leftInfo.maxBSTSubtreeSize;
        }

        //如果右树不为null, 则修改 p2 为 右子树的最大二叉搜索树的个数
        int p2 = -1;
        if (rightInfo != null){
            p2 = rightInfo.maxBSTSubtreeSize;
        }
        
        //只有在左右子树都满足是二叉搜索树的情况下,才更新p3。
        int p3 = -1;
        //左右子树的最大二叉搜索树的个数 = 左右子树整棵树的个数,则说明为二叉搜索树。
        //如果maxBSTSubtreeSize != allSize 则说明之前遍历左右树过程中,出现了 左树最大值 > 当前节点 或 右树最小值 < 当前节点的情况
        boolean isBSTLeft = leftInfo == null ? true : (leftInfo.maxBSTSubtreeSize == leftInfo.allSize);
        boolean isSBTRight = rightInfo == null ? true : (rightInfo.maxBSTSubtreeSize == rightInfo.allSize);

        if (isBSTLeft && isSBTRight){
            //看左子树的最大值 是否小于当前树的值
            //看右子树的最小值 是否小于当前数的值
            boolean leftMaxLessX = leftInfo == null ? true : (leftInfo.max < head.val);
            boolean rightMinMoreX = rightInfo == null ? true : (rightInfo.min > head.val);
			//只有在左右子节点都是二叉搜索树的情况下,更新p3.
            if (leftMaxLessX &&  rightMinMoreX){
                int leftSize = leftInfo == null ? 0 : leftInfo.allSize;
                int rightSize = rightInfo == null ? 0 : rightInfo.allSize;
                p3 = leftSize + rightSize + 1;
            }
        }
        return new Info(Math.max(p3,Math.max(p1,p2)),allSize,max,min);
    }

暴力方式

  1. 将生成的二叉树进行中序遍历(左、头、右)并放进List或Array中
  2. 遍历集合,如果集合中的元素依次都是有小到大的顺序,那说明整棵树都是二叉搜索树(左节点最大值 < 头节点 < 右节点最小值),那直接return 集合的大小。
  3. 如果不满足依次由小到大的顺序,则递归,左右子树找到满足条件的二叉搜索树,并通过Max.math选择较大的一个。

代码

 private static void in(Node head, List<Node> list) {
        if (head == null) {
            return;
        }
        in(head.left, list);
        list.add(head);
        in(head.right, list);
    }
    
private static int largestBSTSubtree1(Node head) {
        if (head == null) {
            return 0;
        }
        List<Node> list = new ArrayList<>();
        //中序遍历
        in(head, list);
        for (int i = 1; i < list.size(); i++) {
            if (list.get(i).val <= list.get(i - 1).val) {
               int leftRes =  largestBSTSubtree1(head.left);
               int rightRes =  largestBSTSubtree1(head.right);
               return Math.max(leftRes,rightRes);
            }
        }
        return list.size();
    }

对数器
递归生成随机二叉树

public static Node generateRandomNode(int maxLength, int maxValue) {
        return generateNode(1, maxLength, maxValue);
    }

    public static Node generateNode(int level, int maxLength, int maxValue) {
        if (level > maxLength || Math.random() < 0.5) {
            return null;
        }
        Node head = new Node((int) (Math.random() * maxValue));
        head.left = generateNode(level + 1, maxLength, maxValue);
        head.right = generateNode(level + 1, maxLength, maxValue);
        return head;
    }

测试

 public static void main(String[] args) {
 		//通过大样本数据量进行测试,如果i1 != i2说明有问题,
        int maxValue = 100;
        int maxLength = 50;
        int testNum = 100000;
        for (int i = 0; i < testNum; i++) {
            Node head = generateRandomNode(maxLength, maxValue);
            int i1 = largestBSTSubtree1(head);
            int i2 = largestBSTSubtree2(head);
            if (i1 != i2){
                System.out.println("Fucking Fuck!!!");
                break;
            }
        }
        System.out.println("finish");
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 判断给定的二叉树是否为二叉排序树,可以按照以下步骤进行: 1. 对于二叉排序树中的任意一个节点,其左子树中的所有节点都小于该节点,其右子树中的所有节点都大于该节点。 2. 对于二叉排序树中的任意一个节点,其左右子树都必须是二叉排序树。 根据以上两点,我们可以得出以下算法: 1. 判断二叉树是否为空树或只有一个节点,如果是,则该二叉树二叉排序树。 2. 对于非空二叉树,取出根节点的值,判断其左子树和右子树是否都为二叉排序树。 3. 对于根节点的左子树,判断其所有节点的值是否都小于根节点的值,如果有任意一个节点的值大于等于根节点的值,则该二叉树不是二叉排序树。 4. 对于根节点的右子树,判断其所有节点的值是否都大于根节点的值,如果有任意一个节点的值小于等于根节点的值,则该二叉树不是二叉排序树。 5. 如果以上所有判断都通过,则该二叉树二叉排序树。 希望这个算法对你有帮助。 <br>### 回答2: 二叉排序树是一种特殊的二叉树,它满足以下条件: 1. 左子树上所有节点的值都小于根节点的值; 2. 右子树上所有节点的值都大于根节点的值; 3. 左右子树都是二叉排序树; 基于以上定义,我们可以得到一个判断一个给定二叉树是否为二叉排序树的算法。该算法主要有以下两步: 1. 中序遍历整棵二叉树,得到一个有序的节点序列,如果这个序列不是有序的,那么该二叉树就不是二叉排序树; 2. 遍历中序遍历得到的有序节点序列,比较相邻两个节点的大小,如果前一个节点的值大于等于后一个节点的值,那么该二叉树就不是二叉排序树,否则它就是一棵二叉排序树。 具体实现上,可以通过递归方式来进行中序遍历。在遍历过程中,将遍历到的节点依次加入到一个序列中,遍历完成后,再遍历一次该序列,判断其中相邻两个节点的大小关系即可。如果是一棵二叉排序树,则序列应该是升序排列的。 该算法的时间复杂度为O(n),其中n为二叉树中节点的个数。具体实现如下: ``` // 判断给定二叉树是否为二叉排序树 bool isBST(TreeNode* root) { vector<int> nodes; // 用于存放中序遍历得到的节点序列 inorderTraversal(root, nodes); // 中序遍历二叉树,得到有序节点序列 int n = nodes.size(); for (int i = 1; i < n; i++) { if (nodes[i] <= nodes[i-1]) { return false; // 如果相邻两个节点的大小关系不满足,返回false } } return true; // 遍历完成后仍没有返回false,说明该二叉树是一棵二叉排序树 } // 中序遍历二叉树,将节点加入到vector中 void inorderTraversal(TreeNode* root, vector<int>& nodes) { if (root == nullptr) { return; } inorderTraversal(root->left, nodes); nodes.push_back(root->val); inorderTraversal(root->right, nodes); } ``` <br>### 回答3: 二叉排序树也叫二叉搜索树,是一种特殊的二叉树。它的左子树上所有节点的值均小于它的根节点的值,而右子树上的所有节点的值均大于它的根节点的值。我们可以通过以下算法判断给定的二叉树是否为二叉排序树。 1. 对于给定的二叉树,判断它是否为空。若为空,直接返回 true。 2. 对于非空的二叉树,判断它的左子树是不是二叉排序树。如果不是,直接返回 false。 3. 判断根节点的值是否大于其左子树最大节点的值。如果不是,直接返回 false。 4. 判断根节点的值是否小于其右子树中最小节点的值。如果不是,直接返回 false。 5. 递归地判断右子树是否为二叉排序树。如果它不是,直接返回 false。 6. 若一直没有返回 false,说明该二叉树二叉排序树,返回 true。 这个算法的主要思路是对于每个节点,都判断其是否满足二叉排序树的性质,并递归地判断其左右子树是否也是二叉排序树。时间复杂度为 O(nlogn) 或 O(n^2),空间复杂度为 O(h),其中 h 为树的高度。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值