leetcode--二叉搜索子树的最大键值和

leetcode地址:二叉搜索子树的最大键值和
给你一棵以 root 为根的 二叉树 ,请你返回 任意 二叉搜索子树的最大键值和。
二叉搜索树的定义如下:
任意节点的左子树中的键值都 小于 此节点的键值。
任意节点的右子树中的键值都 大于 此节点的键值。
任意节点的左子树和右子树都是二叉搜索树。

示例 1:
在这里插入图片描述

输入:root = [1,4,3,2,4,2,5,null,null,null,null,null,null,4,6]
输出:20
解释:键值为 3 的子树是和最大的二叉搜索树。
示例 2:
在这里插入图片描述

输入:root = [4,3,null,1,2]
输出:2
解释:键值为 2 的单节点子树是和最大的二叉搜索树。
示例 3:

输入:root = [-4,-2,-5]
输出:0
解释:所有节点键值都为负数,和最大的二叉搜索树为空。
示例 4:

输入:root = [2,1,3]
输出:6
示例 5:

输入:root = [5,4,8,3,null,6,3]
输出:7

提示:

每棵树有 1 到 40000 个节点。
每个节点的键值在 [-4 * 10^4 , 4 * 10^4] 之间。

实现思路

要解决这个问题,我们需要计算二叉树中每一个子树是否是二叉搜索树(BST),并计算所有BST子树的键值和,最终返回这些BST子树中的最大键值和。

我们可以使用递归的方法来解决这个问题。递归地遍历树中的每一个节点,同时计算子树的信息,包括:

  1. 是否是BST
  2. 子树的键值和
  3. 子树的最小键值
  4. 子树的最大键值

具体步骤如下:

  1. 定义一个辅助函数 dfs(node),它返回四个值:
    is_bst:当前子树是否为BST
    subtree_sum:当前子树的键值和
    min_val:当前子树的最小键值
    max_val:当前子树的最大键值 递归计算左子树和右子树的信息。
  2. 根据左子树和右子树的信息,以及当前节点的值,判断当前子树是否为BST。
  3. 如果是BST,则计算当前子树的键值和、最小键值和最大键值。
  4. 更新最大BST键值和的结果。
  5. 返回当前子树的信息。

代码详解

 假设有以下二叉树:
        1
       / \
      4   3
     /   / \
    2   2   5

首先定义树节点类 TreeNode,用于构建二叉树:

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

TreeNode 类有三个属性:

val:节点的值。
left:左子树。
right:右子树。

接下来是主函数 max_sum_BST,它计算二叉树中任意二叉搜索子树的最大键值和:

def max_sum_BST(root):
    def dfs(node):
        if not node:
            # 空节点被认为是BST,其和为0,最小值为正无穷大,最大值为负无穷大
            return True, 0, float('inf'), float('-inf')

dfs 辅助函数
dfs 函数接收一个节点 node 作为参数,返回四个值:

is_bst:布尔值,表示当前子树是否为BST。
subtree_sum:当前子树的键值和。
min_val:当前子树的最小键值。
max_val:当前子树的最大键值。

若 node 为 None,即为空节点,则返回:

True:空节点被认为是BST。
0:空节点的键值和为0。
float('inf'):空节点的最小键值为正无穷大。
float('-inf'):空节点的最大键值为负无穷大。
  left_is_bst, left_sum, left_min, left_max = dfs(node.left)
  right_is_bst, right_sum, right_min, right_max = dfs(node.right)

递归计算左子树和右子树的信息,包括是否为BST、键值和、最小键值和最大键值。

# 检查当前节点为根的子树是否为BST
if left_is_bst and right_is_bst and left_max < node.val < right_min:
    subtree_sum = left_sum + node.val + right_sum
    max_sum[0] = max(max_sum[0], subtree_sum)
    return True, subtree_sum, min(left_min, node.val), max(right_max, node.val)
else:
    # 当前子树不是BST,返回假
    return False, 0, float('-inf'), float('inf')

检查当前节点为根的子树是否为BST,条件是:

左子树是BST。
右子树是BST。
当前节点的值大于左子树的最大值且小于右子树的最小值。

若满足上述条件,则当前子树是BST:

计算当前子树的键值和 subtree_sum。
更新全局最大BST键值和 max_sum[0]。
返回 True、subtree_sum、当前子树的最小键值和最大键值。
否则,当前子树不是BST,返回 False、键值和0、最小键值为负无穷大、最大键值为正无穷大。
   max_sum = [0]
    dfs(root)
    return max_sum[0]

在 max_sum_BST 函数中:
max_sum 是一个列表,存储最大BST键值和。使用列表是为了在 dfs 函数中能够修改其值。
调用 dfs(root),开始递归遍历树。
返回 max_sum[0],即最大BST键值和。

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def max_sum_BST(root):
    def dfs(node):
        if not node:
            # 空节点被认为是BST,其和为0,最小值为正无穷大,最大值为负无穷大
            return True, 0, float('inf'), float('-inf')
        
        left_is_bst, left_sum, left_min, left_max = dfs(node.left)
        right_is_bst, right_sum, right_min, right_max = dfs(node.right)
        
        # 检查当前节点为根的子树是否为BST
        if left_is_bst and right_is_bst and left_max < node.val < right_min:
            subtree_sum = left_sum + node.val + right_sum
            max_sum[0] = max(max_sum[0], subtree_sum)
            return True, subtree_sum, min(left_min, node.val), max(right_max, node.val)
        else:
            # 当前子树不是BST,返回假
            return False, 0, float('-inf'), float('inf')
    
    max_sum = [0]
    dfs(root)
    return max_sum[0]

# 测试示例
if __name__ == "__main__":
    # 创建测试二叉树
    #        1
    #       / \
    #      4   3
    #     /   / \
    #    2   2   5
    
    root = TreeNode(1)
    root.left = TreeNode(4)
    root.right = TreeNode(3)
    root.left.left = TreeNode(2)
    root.right.left = TreeNode(2)
    root.right.right = TreeNode(5)
    
    result = max_sum_BST(root)
    print(f"最大BST子树的键值和: {result}")  # 应该输出6

GO语言实现

package main

import (
	"fmt"
	"math"
)

// TreeNode 定义二叉树节点
type TreeNode struct {
	Val   int
	Left  *TreeNode
	Right *TreeNode
}

// maxSumBST 函数返回二叉树中任意二叉搜索子树的最大键值和
func maxSumBST(root *TreeNode) int {
	maxSum := 0

	// dfs 辅助函数返回四个值:是否是BST、子树键值和、最小键值、最大键值
	var dfs func(node *TreeNode) (bool, int, int, int)
	dfs = func(node *TreeNode) (bool, int, int, int) {
		if node == nil {
			// 空节点被认为是BST,其和为0,最小值为正无穷大,最大值为负无穷大
			return true, 0, math.MaxInt64, math.MinInt64
		}

		leftIsBST, leftSum, leftMin, leftMax := dfs(node.Left)
		rightIsBST, rightSum, rightMin, rightMax := dfs(node.Right)

		// 检查当前节点为根的子树是否为BST
		if leftIsBST && rightIsBST && leftMax < node.Val && node.Val < rightMin {
			subtreeSum := leftSum + node.Val + rightSum
			if subtreeSum > maxSum {
				maxSum = subtreeSum
			}
			return true, subtreeSum, min(leftMin, node.Val), max(rightMax, node.Val)
		}

		// 当前子树不是BST,返回假
		return false, 0, math.MinInt64, math.MaxInt64
	}

	dfs(root)
	return maxSum
}

// 辅助函数:返回两个整数中的较小值
func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

// 辅助函数:返回两个整数中的较大值
func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

// 测试示例
func main() {
	// 创建测试二叉树
	//        1
	//       / \
	//      4   3
	//     /   / \
	//    2   2   5
	root := &TreeNode{Val: 1}
	root.Left = &TreeNode{Val: 4}
	root.Right = &TreeNode{Val: 3}
	root.Left.Left = &TreeNode{Val: 2}
	root.Right.Left = &TreeNode{Val: 2}
	root.Right.Right = &TreeNode{Val: 5}

	result := maxSumBST(root)
	fmt.Printf("最大BST子树的键值和: %d\n", result) // 应该输出6
}

kotlin实现

// 定义二叉树节点类
class TreeNode(var `val`: Int) {
    var left: TreeNode? = null
    var right: TreeNode? = null
}

// maxSumBST 函数返回二叉树中任意二叉搜索子树的最大键值和
fun maxSumBST(root: TreeNode?): Int {
    var maxSum = 0

    // dfs 辅助函数返回四个值:是否是BST、子树键值和、最小键值、最大键值
    fun dfs(node: TreeNode?): Quad<Boolean, Int, Int, Int> {
        if (node == null) {
            // 空节点被认为是BST,其和为0,最小值为正无穷大,最大值为负无穷大
            return Quad(true, 0, Int.MAX_VALUE, Int.MIN_VALUE)
        }

        val (leftIsBST, leftSum, leftMin, leftMax) = dfs(node.left)
        val (rightIsBST, rightSum, rightMin, rightMax) = dfs(node.right)

        // 检查当前节点为根的子树是否为BST
        if (leftIsBST && rightIsBST && leftMax < node.`val` && node.`val` < rightMin) {
            val subtreeSum = leftSum + node.`val` + rightSum
            if (subtreeSum > maxSum) {
                maxSum = subtreeSum
            }
            return Quad(true, subtreeSum, minOf(leftMin, node.`val`), maxOf(rightMax, node.`val`))
        }

        // 当前子树不是BST,返回假
        return Quad(false, 0, Int.MIN_VALUE, Int.MAX_VALUE)
    }

    dfs(root)
    return maxSum
}

// Quad 数据类,用于返回四个值
data class Quad<A, B, C, D>(val first: A, val second: B, val third: C, val fourth: D)

// 测试示例
fun main() {
    // 创建测试二叉树
    //        1
    //       / \
    //      4   3
    //     /   / \
    //    2   2   5
    val root = TreeNode(1)
    root.left = TreeNode(4)
    root.right = TreeNode(3)
    root.left?.left = TreeNode(2)
    root.right?.left = TreeNode(2)
    root.right?.right = TreeNode(5)

    val result = maxSumBST(root)
    println("最大BST子树的键值和: $result") // 应该输出6
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/773849.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【matlab 路径规划】基于改进遗传粒子群算法的药店配送路径优化

一 背景介绍 本文分享的是一个基于订单合并的订单分配和路径规划联合优化&#xff0c;主要背景是骑手根据客户需求&#xff0c;从药店取药之后进行配送&#xff0c;配送的过程中考虑路径的长度、客户的服务时间窗、车辆的固定成本等要素&#xff0c;经过建模和优化得到最优的配…

什么是声明式编程?发展趋势怎么样的?

一、什么是声明式编程&#xff1f; 声明式编程&#xff08;Declarative programming&#xff09;是一种编程范式&#xff0c;与命令式编程相对立。它主要描述目标的性质&#xff0c;让计算机明白目标&#xff0c;而非具体的执行流程。在声明式编程中&#xff0c;开发者只需声明…

彻底搞懂Kafka生产消费流程,这篇文章就够了!

Hey, 小伙伴们!今天小米给大家带来一篇关于Kafka生产消费基本流程的揭秘,内容超干货!让我们一起揭开Kafka神秘的面纱,探索它的工作原理吧! Producer创建及其内部结构 当我们创建一个Kafka Producer时,Kafka会为我们创建一个叫做Sender的线程,并将其设置为守护线程(Da…

论文解读StyleGAN系列——StyleGANv3

论文&#xff1a;Alias-Free Generative Adversarial Networks&#xff08;2021.06&#xff09; 作者&#xff1a;Tero Karras, Miika Aittala, Samuli Laine, Erik Hrknen, Janne Hellsten, Jaakko Lehtinen, Timo Aila 链接&#xff1a;https://arxiv.org/abs/2106.12423 代码…

计算两个经纬度之间的球面距离(基于Mysql和PHP实现)

计算两个经纬度之间的球面距离 1、MySQL实现方式 - 基于空间函数(ST_Distance_Sphere)实现 前置条件&#xff1a;确保您使用的是 MySQL 8.0 或更高版本&#xff0c;因为较早的版本对地理空间的支持有限。 1.1 创建表和索引 说明&#xff1a;设置 location 为 point 类型 #…

驭码CodeRider将亮相世界人工智能大会,AI 产品、重磅分享,真的很City!

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab &#xff1a;https://gitlab.cn/install?channelcontent&utm_sourcecsdn 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署…

Redis 中 Set 和 Zset 类型

目录 1.Set类型 1.1 Set集合 1.2 普通命令 1.3 集合操作 1.4 内部编码 1.5 使用场景 2.Zset类型 2.1 Zset有序集合 2.2 普通命令 2.3 集合间操作 2.4 内部编码 2.5 使用场景 1.Set类型 1.1 Set集合 集合类型也是保存多个字符串类型的元素&#xff0c;但是和列表类型不同的是&…

LVS+Keepalived 实现高可用负载均衡

前言 在业务量达到一定量的时候&#xff0c;往往单机的服务是会出现瓶颈的。此时最常见的方式就是通过负载均衡来进行横向扩展。其中我们最常用的软件就是 Nginx。通过其反向代理的能力能够轻松实现负载均衡&#xff0c;当有服务出现异常&#xff0c;也能够自动剔除。但是负载…

基于Redisson实现分布式锁

基于redisson实现分布式锁 之前背过分布式锁几种实现方案的八股文&#xff0c;但是并没有真正自己实操过。现在对AOP有了更深一点的理解&#xff0c;就自己来实现一遍。 1、分布式锁的基础知识 分布式锁是相对于普通的锁的。普通的锁在具体的方法层面去锁&#xff0c;单体应…

搜维尔科技:详谈ART的工具追踪技术

您的生产流程中是否已经受益于刀具跟踪系统&#xff1f;您是否意识到它们的价值&#xff1f;因为它们可以优化您的装配顺序&#xff0c;从而节省您的时间和金钱。 目前我们提供两种工具跟踪解决方案&#xff1a; 1.ART与 VERPOSE的解决方案——易于使用的图像识别 安装在工…

探索智能合约在医疗健康领域的革新应用

随着区块链技术的发展&#xff0c;智能合约作为其重要应用之一&#xff0c;在医疗健康领域展示了巨大的潜力和革新性。智能合约是一种基于区块链的自动化执行协议&#xff0c;它可以在无需中介的情况下执行和验证合同。在医疗健康领域&#xff0c;智能合约不仅简化了数据管理和…

房屋租赁管理小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;中介管理&#xff0c;房屋信息管理&#xff0c;房屋类型管理&#xff0c;租房订单管理&#xff0c;租房信息管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;房屋信息&a…

ctfshow-web入门-命令执行(web66-web70)

目录 1、web66 2、web67 3、web68 4、web69 5、web70 1、web66 show_source 被禁用 highlight_file 发现 flag 不在 flag.php 里面 先使用 scandir() 进行目录扫描&#xff1a; cprint_r(scandir("./")); 当前目录下只有 index.php 和 flag.php 扫一下根目…

图书商城系统java项目ssm项目jsp项目java课程设计java毕业设计

文章目录 图书商城系统一、项目演示二、项目介绍三、部分功能截图四、部分代码展示五、底部获取项目源码&#xff08;9.9&#xffe5;带走&#xff09; 图书商城系统 一、项目演示 图书商城系统 二、项目介绍 语言: Java 数据库&#xff1a;MySQL 技术栈&#xff1a;SpringS…

「ETL趋势」FDL定时任务区分开发/生产模式、API输入输出支持自定义响应解析

FineDataLink作为一款市场上的顶尖ETL工具&#xff0c;集实时数据同步、ELT/ETL数据处理、数据服务和系统管理于一体的数据集成工具&#xff0c;进行了新的维护迭代。本文把FDL4.1.7最新功能作了介绍&#xff0c;方便大家对比&#xff1a;&#xff08;产品更新详情&#xff1a;…

spark shuffle——shuffle管理

ShuffleManager shuffle系统的入口。ShuffleManager在driver和executor中的sparkEnv中创建。在driver中注册shuffle&#xff0c;在executor中读取和写入数据。 registerShuffle&#xff1a;注册shuffle&#xff0c;返回shuffleHandle unregisterShuffle&#xff1a;移除shuff…

LED显示屏跟COB显示屏有哪些不同?

COB显示屏跟LED显示屏的主要区别在于产品的显示效果、封装技术、耐用性、防护力、维护以及制造成本方面的不同&#xff0c;这里所说的LED显示屏主要指的是使用SMD封装的LED显示屏&#xff0c;今天跟随COB显示屏厂家中品瑞科技一起来详细看看具体分析&#xff1a; 一、封装技术 …

视图库对接系列(GA-T 1400)九、视图库对接系列(本级)机动车数据推送

背景 在上几章中,我们已经可以将视图库的平台写到我们的数据库中了。 换句话说就已经接入我们的平台了,这几期的话,我们就对接设备, 将设备的数据接入到我们平台来。 机动车数据推送 接入机动车数据推送相对比较简单,我们只需要实现对应的接口就ok了。 具体如图: 有增…

77. UE5 RPG 创建角色的技能栏

在前面的文章里&#xff0c;我们实现了角色属性技能和场景。接下来&#xff0c;我们要优化角色显示UI&#xff0c;在屏幕底部显示角色血量&#xff0c;蓝量&#xff0c;技能和经验值。 创建新的用户控件 选择创建新的控件蓝图 父类为我们自定义的RPGUserWidget&#xff0c;这…

这样拼板帮你省近万元,堪称PCB工程师成本终结者!

别再被骗了&#xff0c;打PCB板价格高不是单价高&#xff01;而是你的拼板导致利用率太低了&#xff01; 今天给大家讲个小故事&#xff0c;教大家如何省钱...... 一个爽朗的晴天&#xff0c;我听闻同事说有客户对他吐槽打板子价格太高&#xff0c;说着说着就开始吹起了牛逼...…
最新文章