求二叉树中最大的二叉搜索子树的头节点

二叉树,最大,二叉,搜索,节点 · 浏览次数 : 61

小编点评

**算法和数据结构笔记** **排版** * 使用 ArrayList 和 in 方法进行排版。 * 使用 ArrayList 和 Process 方法进行排版。 * 使用 ArrayList 和 Collections类进行排版。 **算法** * **最大子树的算法 1**:递归搜索,使用 maxSubBSTHead1 方法求最大子树的最小值。 * **最大子树的算法 2**:深度优先搜索,使用 maxSubBSTHead2 方法求最大子树的最小值。 **数据结构** * **ArrayList**:用于存储排版的元素。 * **TreeNode**:用于存储最大子树的节点。 * **Collections**类:用于存储各种数据结构。 **算法的详细说明** * **最大子树的算法 1**: * 使用递归搜索求最大子树的最小值。 * 在每个递归调用中,更新最小值。 * 返回最小值。 * **最大子树的算法 2**: * 使用深度优先搜索求最大子树的最小值。 * 在每个深度优先搜索调用中,更新最小值。 * 返回最小值。 **数据结构的详细说明** * **ArrayList**: * 使用 ArrayList 的 add 方法添加元素。 * 使用 ArrayList 的 get 方法获取元素。 * 使用 ArrayList 的 size 方法获取元素数量。 * **TreeNode**: * 使用 TreeNode 的 val 属性存储元素值。 * 使用 TreeNode 的 left 和 right 属性存储子树的节点。 * 使用 TreeNode 的 maxSubBSTHead 和 maxSubBSTSize 属性存储最大子树的最小值和最大子树的最小值。 **算法的性能** * 大数据算法的性能通常取决于排版的性能。 * 最速算法的性能通常取决于深度优先搜索的性能。 **数据结构的性能** * 大数据算法的性能通常取决于存储的性能。 * 使用 ArrayList 和 Collections类存储的性能通常较高。

正文

求二叉树中最大的二叉搜索子树的头节点

作者:Grey

原文地址:

博客园:求二叉树中最大的二叉搜索子树的头节点

CSDN:求二叉树中最大的二叉搜索子树的头节点

题目描述

给定一棵二叉树的头节点head, 返回这颗二叉树中最大的二叉搜索子树的头节点。

暴力解法

定义递归函数

TreeNode maxSubBSTHead1(TreeNode head)

递归含义表示:以head为头的二叉树中最大的二叉搜索子树的头结点是什么。

接下来是 base case,

    if (head == null) {
      return null;
    }

定义一个辅助函数getBSTSize(head),这个函数表示:如果以head为头的树是二叉搜索树,则返回其大小,否则返回 0。

getBSTSize(head)的实现思路也比较简单,即通过中序遍历收集以 head 为头的树,如果这个树满足二叉搜索子树,则返回二叉搜索子树的大小,如果以 head 的头不是二叉搜索树,直接返回 0。

代码如下

  public static int getBSTSize(TreeNode head) {
    if (head == null) {
      return 0;
    }
    ArrayList<TreeNode> arr = new ArrayList<>();
    // 中序遍历收集以 head 为头的二叉树,存在数组中
    in(head, arr);
    for (int i = 1; i < arr.size(); i++) {
      if (arr.get(i).val <= arr.get(i - 1).val) {
        return 0;
      }
    }
    return arr.size();
  }

实现了如上方法,主函数直接做如下调用即可,代码说明见注释:

  
  public static TreeNode maxSubBSTHead1(TreeNode head) {
    if (head == null) {
      return null;
    }
    // 以 head 为头的二叉搜索子树大小不为0,说明head这就是最大的二叉搜索子树头!
    if (getBSTSize(head) != 0) {
      return head;
    }
    // 去左树上找哪个结点是最大二叉搜索子树的头结点
    TreeNode leftAns = maxSubBSTHead1(head.left);
    // 去右树上找哪个结点是最大二叉搜索子树的头结点
    TreeNode rightAns = maxSubBSTHead1(head.right);
    // 左右树哪个二叉搜索子树更大,就返回哪个结点
    return getBSTSize(leftAns) >= getBSTSize(rightAns) ? leftAns : rightAns;
  }

二叉树的递归套路

定义如下数据结构

  public static class Info {
    public TreeNode maxSubBSTHead;
    public int maxSubBSTSize;
    public int min;
    public int max;

    public Info(TreeNode h, int size, int mi, int ma) {
      maxSubBSTHead = h;
      maxSubBSTSize = size;
      min = mi;
      max = ma;
    }
  }

针对每一颗子树,都有如上结构信息,其中

maxSubBSTHead: 表示某个子树的最大二叉搜索子树的头结点

maxSubBSTSize: 表示某个结点如果是二叉搜索树,其大小为多少

min:表示以某个结点为头的树的最小值是多少

max:表示以某个结点为头的树的最大值是多少

接下来定义递归函数

Info process(TreeNode X)

以 X 为头的树,返回对应的 Info

接下来整理可能性

  1. 如果 X == null 则直接返回 null,即 base case;

  2. 接下来问左树要 Info 信息,再问右树要 Info 信息,整合成 head 的 info 信息,以代码注释来说明

// 问左树要信息
    Info leftInfo = process(X.left);
    // 问右树要信息
    Info rightInfo = process(X.right);
    int min = X.val;
    int max = X.val;
    TreeNode maxSubBSTHead = null;
    int maxSubBSTSize = 0;
    
    if (leftInfo != null) {
      // 左树信息不为 null
      // 则 head.val 和 左树的min PK,谁小谁是以head 为头的min 信息
      min = Math.min(min, leftInfo.min);
      // 则 head.val 和 左树的max PK,谁大谁是以head 为头的max 信息
      max = Math.max(max, leftInfo.max);
      // 以 head 为头的最大二叉搜索子树的头结点至少是leftInfo.maxSubBSTHead
      maxSubBSTHead = leftInfo.maxSubBSTHead;
      // 以 head 为头的最大二叉搜索子树的头结点大小至少是leftInfo.maxSubBSTSize
      maxSubBSTSize = leftInfo.maxSubBSTSize;
    }
    if (rightInfo != null) {
      // 右树信息不为 null 
      // 思路和 左树信息不为 null 一样
      min = Math.min(min, rightInfo.min);
      max = Math.max(max, rightInfo.max);
      if (rightInfo.maxSubBSTSize > maxSubBSTSize) {
        maxSubBSTHead = rightInfo.maxSubBSTHead;
        maxSubBSTSize = rightInfo.maxSubBSTSize;
      }
    }
    // 到了这一步,说明 leftInfo 和 rightInfo 至少有一个为 null
    // 不管哪个为null,如果要以 X 为最大二叉搜索子树的头结点,则需要满足以下条件
    // 1. leftInfo.maxSubBSTHead == X.left && leftInfo.max < X.val
    // 2. rightInfo.maxSubBSTHead == X.right && rightInfo.min > X.val
    if ((leftInfo == null || (leftInfo.maxSubBSTHead == X.left && leftInfo.max < X.val))
        && (rightInfo == null || (rightInfo.maxSubBSTHead == X.right && rightInfo.min > X.val))) {
      maxSubBSTHead = X;
      maxSubBSTSize =
          (leftInfo == null ? 0 : leftInfo.maxSubBSTSize)
              + (rightInfo == null ? 0 : rightInfo.maxSubBSTSize)
              + 1;
    }
    return new Info(maxSubBSTHead, maxSubBSTSize, min, max);

两个思路完整代码如下(含测试代码)

import java.util.ArrayList;

public class Code_MaxSubBSTHead {

  public static class TreeNode {
    public int val;
    public TreeNode left;
    public TreeNode right;

    public TreeNode(int data) {
      this.val = data;
    }
  }

  public static int getBSTSize(TreeNode head) {
    if (head == null) {
      return 0;
    }
    ArrayList<TreeNode> arr = new ArrayList<>();
    in(head, arr);
    for (int i = 1; i < arr.size(); i++) {
      if (arr.get(i).val <= arr.get(i - 1).val) {
        return 0;
      }
    }
    return arr.size();
  }

  public static void in(TreeNode head, ArrayList<TreeNode> arr) {
    if (head == null) {
      return;
    }
    in(head.left, arr);
    arr.add(head);
    in(head.right, arr);
  }

  public static TreeNode maxSubBSTHead1(TreeNode head) {
    if (head == null) {
      return null;
    }
    if (getBSTSize(head) != 0) {
      return head;
    }
    TreeNode leftAns = maxSubBSTHead1(head.left);
    TreeNode rightAns = maxSubBSTHead1(head.right);
    return getBSTSize(leftAns) >= getBSTSize(rightAns) ? leftAns : rightAns;
  }

  public static TreeNode maxSubBSTHead2(TreeNode head) {
    if (head == null) {
      return null;
    }
    return process(head).maxSubBSTHead;
  }

  // 每一棵子树
  public static class Info {
    public TreeNode maxSubBSTHead;
    public int maxSubBSTSize;
    public int min;
    public int max;

    public Info(TreeNode h, int size, int mi, int ma) {
      maxSubBSTHead = h;
      maxSubBSTSize = size;
      min = mi;
      max = ma;
    }
  }

  public static Info process(TreeNode X) {
    if (X == null) {
      return null;
    }
    Info leftInfo = process(X.left);
    Info rightInfo = process(X.right);
    int min = X.val;
    int max = X.val;
    TreeNode maxSubBSTHead = null;
    int maxSubBSTSize = 0;
    if (leftInfo != null) {
      min = Math.min(min, leftInfo.min);
      max = Math.max(max, leftInfo.max);
      maxSubBSTHead = leftInfo.maxSubBSTHead;
      maxSubBSTSize = leftInfo.maxSubBSTSize;
    }
    if (rightInfo != null) {
      min = Math.min(min, rightInfo.min);
      max = Math.max(max, rightInfo.max);
      if (rightInfo.maxSubBSTSize > maxSubBSTSize) {
        maxSubBSTHead = rightInfo.maxSubBSTHead;
        maxSubBSTSize = rightInfo.maxSubBSTSize;
      }
    }
    if ((leftInfo == null ? true : (leftInfo.maxSubBSTHead == X.left && leftInfo.max < X.val))
        && (rightInfo == null
            ? true
            : (rightInfo.maxSubBSTHead == X.right && rightInfo.min > X.val))) {
      maxSubBSTHead = X;
      maxSubBSTSize =
          (leftInfo == null ? 0 : leftInfo.maxSubBSTSize)
              + (rightInfo == null ? 0 : rightInfo.maxSubBSTSize)
              + 1;
    }
    return new Info(maxSubBSTHead, maxSubBSTSize, min, max);
  }

  // for test
  public static TreeNode generateRandomBST(int maxLevel, int maxValue) {
    return generate(1, maxLevel, maxValue);
  }

  // for test
  public static TreeNode generate(int level, int maxLevel, int maxValue) {
    if (level > maxLevel || Math.random() < 0.5) {
      return null;
    }
    TreeNode head = new TreeNode((int) (Math.random() * maxValue));
    head.left = generate(level + 1, maxLevel, maxValue);
    head.right = generate(level + 1, maxLevel, maxValue);
    return head;
  }

  public static void main(String[] args) {
    int maxLevel = 4;
    int maxValue = 100;
    int testTimes = 1000000;
    for (int i = 0; i < testTimes; i++) {
      TreeNode head = generateRandomBST(maxLevel, maxValue);
      if (maxSubBSTHead1(head) != maxSubBSTHead2(head)) {
        System.out.println("Oops!");
      }
    }
    System.out.println("finish!");
  }
}

更多

算法和数据结构笔记

与求二叉树中最大的二叉搜索子树的头节点相似的内容:

求二叉树中最大的二叉搜索子树的头节点

求二叉树中最大的二叉搜索子树的头节点 作者:Grey 原文地址: 博客园:求二叉树中最大的二叉搜索子树的头节点 CSDN:求二叉树中最大的二叉搜索子树的头节点 题目描述 给定一棵二叉树的头节点head, 返回这颗二叉树中最大的二叉搜索子树的头节点。 暴力解法 定义递归函数 TreeNode maxS

二叉树的最大宽度系列问题

二叉树的最大宽度系列问题 作者:Grey 原文地址: 博客园:二叉树的最大宽度系列问题 CSDN:二叉树的最大宽度系列问题 求树的最大宽度 题目描述 给你一棵二叉树的根节点 root ,返回树的最大宽度 。 树的最大宽度是所有层中最大的宽度 。 每一层的宽度被定义为该层最左和最右的非空节点(即,两个

与堆和堆排序相关的问题

与堆和堆排序相关的问题 作者:Grey 原文地址: 博客园:与堆和堆排序相关的问题 CSDN:与堆和堆排序相关的问题 堆结构说明 堆结构就是用数组实现的完全二叉树结构,什么是完全二叉树?可以参考如下两篇博客: 使用二叉树的递归套路来解决的问题 快速求完全二叉树的节点个数 完全二叉树中如果每棵子树的最

二叉树中查找后继节点问题

二叉树中查找后继节点问题 作者:Grey 原文地址: 博客园:二叉树中查找后继节点问题 CSDN:二叉树中查找后继节点问题 题目描述 给定一个二叉查找树,以及一个节点,求该节点在中序遍历的后继,如果没有则返回 null 题目链接见:LintCode 448 · Inorder Successor i

[转帖]Redis学习四(运维指南).

阅读目录 一、上线规划 二、常见运维操作 三、测试方法 回到顶部 一、上线规划 一般 redis 的参数配置都在 redis.conf 中,在上线前根据实际环境配置好合适参数,能有效提高 redis 的可用性。 redis 的运行机器 CPU 不求核数多,但求主频高,Cache大,因为 redis

高一下三调模拟赛5.13(附关于二分图匈牙利建边的详细思考)

前言注:本篇为知识性内容,A题附详解关于匈牙利算法求最大独立子集难以理解的建边问题的思考,若有不当之处感谢指出。暂时只写了A篇题解,以供帮助大家理解相关问题,剩余题解会进行补充。 又是小集训的一周,总要伴随着模拟赛... 还是五道题目: A. 攻击装置 B. 循环 C. 漫步 D. 穿越 E. 结队

[转帖]linux求数组的交集,shell/bash 交集、并集、差集

方法一(直接用文件名):取两个文本文件的并集、交集、差集 并: sort -m 交: sort -m 差 file1 - file2: sort -m 方法二(用变量参数):取两个文本文件的并集、交集、差集 file1=XXXX file2=YYYY # 并: sort -m # 交: sort -

2023-9-21 闲话

鲜花还是在博客园写吧。 感觉挺累的,想病个两三天回家睡觉。 推歌:竹ノ花 原曲之一是《东方求闻史记》的附赠曲,同样改编了本曲的二创还有《现梦 -genmu-》 都是挺让人伤感的歌曲呢,这首歌是凋叶棕为同名本子做的曲,讲的是稗田三代家主与男主的故事。 稗田家的家主 30 岁必死,然后转生,然后还有一堆

Tarjan 求有向图的强连通分量

重温Tarjan, 网上看了许多博客感觉都讲的不清楚. 故传上来自己的笔记, 希望帮到大家. 提到的一些概念可以参考 oi wiki, 代码也是 oi wiki 的, 因为我不认为我能写出比大佬更好的代码了. 强连通分量: 有向图的最大强连通子图 ( 有向图中任意两点可达 ) Tarjan 对每个结

KPM算法求字符串的最小周期证明

先给出公式 ans = n - LPS[n-1] 其中ans为最小周期,n为给出的由假设的周期字符串中提取出的子串长度,LPS为前缀函数,n-1为字符串最后的位置下标 证明如下 证明ans = n - LPS[n-1],思路: (1) 证明特殊情况,即先对完整周期字符串进行证明,这时候的字符串组成是