代码随想录27期|Python|Day21|二叉树| 530.二叉搜索树的最小绝对差| 501.二叉搜索树中的众数| 236. 二叉树的最近公共祖先

news2024/12/25 16:08:33

特别需要注意题目中给的隐藏信息(比如这里的BST) 

530. 二叉搜索树的最小绝对差

前两个是BST的经典递归模版解法,后面一个迭代的解法可以当作BST的一般迭代规则。

转换成数组

根据一般的递归模版

    def traversal(self, root):
        if not root:
            return
        self.traversal(root.left)
        self.vec.append(root.val)
        self.traversal(root.right)

在根据Day20的查找元素for循环的方法进行数组的遍历。 

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def __init__(self):
        self.vec = []

    def getMinimumDifference(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        self.vec = []
        result = float('inf')
        self.traversal(root)
        # 在有序数组里面,最小值只可能是相邻的
        for i in range(1, len(self.vec)):
            if self.vec[i] - self.vec[i - 1] <= result:
                result = self.vec[i] - self.vec[i - 1]
        return result

    def traversal(self, root):
        if not root:
            return
        self.traversal(root.left)
        self.vec.append(root.val)
        self.traversal(root.right)

设定+更新最小值

在查找BST的基础上加入更新全局最小值的操作。

注意if pre is not None的判断语句用来排除初始化情况。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def __init__(self):
        self.min_value = float('inf')  # 初始化为最大的int之外的数字
        self.pre = None

    def getMinimumDifference(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        # 递归法
        self.traversal_2(root)
        return self.min_value
    
    def traversal_2(self, root):
        if not root:
            return
        self.traversal_2(root.left)
        if self.pre is not None:
            self.min_value = min(self.min_value, root.val - self.pre.val)
        self.pre = root
        self.traversal_2(root.right)

迭代法(BST的一般迭代过程)

    def getMinimumDifference(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        # 迭代法
        stack = []
        pre = None
        cur = root
        global_min = float('inf')
        
        # 当前不是空节点或者栈里还有没有遍历完的元素的时候
        while cur is not None or len(stack) > 0:
            # 遍历所有的左侧节点(先找最小值)
            if cur is not None:
                stack.append(cur)
                cur = cur.left
            else:
                # 依次回溯
                cur = stack.pop()
                if pre is not None:
                    global_min = min(global_min, cur.val - pre.val)
                pre = cur
                cur = cur.right
        return global_min

其中注意到和找最小值递归类似,都存在一个固定的模版函数体

                """
                左侧节点处理
                """
                if pre is not None:
                    global_min = min(global_min, cur.val - pre.val)
                pre = cur
                """
                右侧节点处理
                """

从这个过程我们也可以看出,右侧节点的处理仅仅是完成了一个位置的移动,所以我们不妨只从左侧子树的遍历(斜着遍历)看一个BST。

501. 二叉搜索树中的众数

字典+for循环遍历(算两遍)

先找到频率对应的字典,然后找频率的最大值。

缺点是对于时间要求比较高。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
from collections import defaultdict
class Solution(object):
    def BSTsearch(self, cur, freq_map):
        if cur is None:
            return
        freq_map[cur.val] += 1  # 统计出现频率
        self.BSTsearch(cur.left, freq_map)
        self.BSTsearch(cur.right, freq_map)

    def findMode(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        # 字典统计+算两遍
        freq_map = defaultdict(int)  # 初始化字典
        res = []
        if not root:
            return res
        self.BSTsearch(root, freq_map)
        # 取出最大值
        max_freq = max(freq_map.values())
        for key, freq in freq_map.items():
            if freq == max_freq:  # 算两遍找最大值
                res.append(key)
        return res

BST性质搜索+双指针

利用BST性质,相同的字符(如果存在)必定是连续的(单调性),所以只需要算连续出现的频率即可。

需要注意:res结果保存树数组在找到新的最大频率之后需要进行及时的更新

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
from collections import defaultdict

class Solution(object):
    def __init__(self):
        self.res = []
        self.pre = None
        self.max_freq = 0
        self.cur_freq = 0

    def findMode(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        # 双指针
        self.BSTsearch_2(root)
        return self.res

    def BSTsearch_2(self, cur):
        if not cur:
            return

        self.BSTsearch_2(cur.left)

        if self.pre is None:  # 前一个节点是空节点说明现在的节点是叶子节点,初始化为1
            self.cur_freq = 1
        elif cur.val == self.pre.val:  # 和前一个节点相等 + 1
            self.cur_freq += 1
        else:  # 和前一个节点不相等,初始化为1
            self.cur_freq = 1
        self.pre = cur

        if self.cur_freq == self.max_freq:
            self.res.append(cur.val)
        elif self.cur_freq > self.max_freq:
            # 注意全局变量的更新,特别是答案数组的更新
            self.max_freq = self.cur_freq
            self.res = [cur.val]

        self.BSTsearch_2(cur.right)
        return 

 236. 二叉树的最近公共祖先

注意题目条件:所有的数值都不相同。

一个基本的思路:只要找到了距离p、q深度最小的一个节点,使得其左右节点有一个包含p、q中的某一个,那么这个节点就是要找的节点。

但是遇到一个问题:如果另外一个节点不在这个根节点的子树里面。这是需要运用到递归的思想,也就是返回值是返回给上一层根节点的值,也就是root是返回给上一层root的,在上一个函数当中还会进一步递归。

这里引入一个返回值实际上是root的“标记值”的概念:只在一个当前root的子树当中找到了一个目标值,也就意味着上一层的root被标记为这个root的值,在上一层的root左右子树没有找到另外一个值的时候,更新标记的root为上一层,再往上返回递归。其实也就是一个回溯的过程

这个过程的实现体现在以下的函数结构当中:

        if left != None and right != None:  # 当前左右都找到,返回当前节点(就是要找的)
            return root
        # 左或者右没找到,返回找到的那个给中间节点(代表这个子树包含了其中一个)
        if left == None and right != None:
            return right
        elif left != None and right == None:
            return left
        else:  # 其他情况说明不在这个子树里
            return None

也可以简化为: 

        if left is not None and right is not None:
        return root

        if left is None:
            return right
        return left

本题需要从p、q(也就是底层)出发,向上找根节点,所以顺序采用的是后序遍历+回溯的方法。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def lowestCommonAncestor(self, root, p, q):
        """
        :type root: TreeNode
        :type p: TreeNode
        :type q: TreeNode
        :rtype: TreeNode
        """
        # 终止条件:当前节点是空 或者 找到了p、q中的一个节点
        if not root:
            return root
        elif root == p or root == q:
            return root
        # 左右遍历
        left = self.lowestCommonAncestor(root.left, p, q)
        right = self.lowestCommonAncestor(root.right, p, q)
        # 中间节点处理
        if left != None and right != None:  # 当前左右都找到,返回当前节点(就是要找的)
            return root
        # 左或者右没找到,返回找到的那个给中间节点(代表这个子树包含了其中一个)
        if left == None and right != None:
            return right
        elif left != None and right == None:
            return left
        else:  # 其他情况说明不在这个子树里
            return None

还有一个困惑:为什么一定要遍历整个树?是否只需要找到一个路径就返回?

实际上不可以,因为往上返回的值是依赖左右子树搜索的反馈进行的,也就是说需要左右子树的返回结果的时候,即使是“找到一个满足条件的即可”也需要遍历整个树。

OMG第21天完结🎉

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用23种设计模式打造一个cocos creator的游戏框架----(二十三)中介者模式

1、模式标准 模式名称&#xff1a;中介者模式 模式分类&#xff1a;行为型 模式意图&#xff1a;用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用&#xff0c;从而使其耦合松散&#xff0c;而且可以独立地改变它们之间的交互。 结构图&#xff…

基于SSM框架的电脑测评系统论文

基于 SSM框架的电脑测评系统 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;作为一个一般的用户都开始注重与自己的信息展示平台&#xff0c;实现基于SSM框架的电脑测评系统在技术上已成熟。本文介绍了基于SSM框架的电脑测评系统的开发全过程。通过分析用户对于…

【小黑嵌入式系统第十一课】μC/OS-III程序设计基础(一)——任务设计、任务管理(创建基本状态内部任务)、任务调度、系统函数

上一课&#xff1a; 【小黑嵌入式系统第十课】μC/OS-III概况——实时操作系统的特点、基本概念&#xff08;内核&任务&中断&#xff09;、与硬件的关系&实现 文章目录 一、任务设计1.1 任务概述1.2 任务的类型1.2.1 单次执行类任务&#xff08;运行至完成型&#…

ai学习笔记-入门

目录 一、人工智能是什么&#xff1f;可以做什么&#xff1f; 人工智能(Artificial Intelligence): 人工智能的技术发展路线&#xff1a; 产业发展驱动因素&#xff1a;数据、算力、算法 二、人工智能这个工具的使用原理入门 神经网络⭕数学基础 1.神经网络的生物表示 …

成都爱尔蔡裕主任提醒眼前有条状黑影飘动,该治疗吗?

眼前有好多影子&#xff0c;有的看起来是黑色有的仿佛透明&#xff0c;呈现条状、点状&#xff0c;它们还跟随脑袋的移动而移动&#xff0c;仿佛在眼前打转&#xff0c;尤其在阳光明媚的时候或者注视白墙壁时尤为明显。 这是病吗?需要治疗吗? 飞蚊症 飞蚊症在医学上称为“玻璃…

JavaScript系列-循环语句

文章目录 1. JavaScript 函数常用的循环语句有以下1 打遍所有可循环对象的 for 循环2 for in &#xff1a;遍历对象3 for of &#xff1a;遍历有迭代器对象&#xff0c;如数组4 while 循环5 do while6 switch case 2.各循环方法的使用场景和方法for 循环第一种用法&#xff08;…

Java-Secruity-2

可以先看这篇文章 Secruity-1&#x1f448; 1、授权 1.1 权限管理 在日常使用的系统中都会涉及到权限相关的操作&#xff0c;管理员有管理员的操作&#xff0c;用户有用户的操作&#xff0c;不同的用户可以使用不同的功能&#xff0c;这需要使用到权限管理。 所以在写接口…

openGauss学习笔记-168 openGauss 数据库运维-备份与恢复-导入数据-使用gs_restore命令导入数据

文章目录 openGauss学习笔记-168 openGauss 数据库运维-备份与恢复-导入数据-使用gs_restore命令导入数据168.1 操作场景168.2 操作步骤168.3 示例 openGauss学习笔记-168 openGauss 数据库运维-备份与恢复-导入数据-使用gs_restore命令导入数据 168.1 操作场景 gs_restore是…

PyQt6 信号与槽

锋哥原创的PyQt6视频教程&#xff1a; 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计51条视频&#xff0c;包括&#xff1a;2024版 PyQt6 Python桌面开发 视频教程(无废话版…

makefile例子

1、目录结构 2、文件 2.1、 test.h extern void test(void); 2.2 、test.c #include <stdio.h>void test(void) {printf("Hello world!\n"); }2.3 、main.c #include "test.h"int main(void) {test();return 0; }2.4、makefile TEST_DIR : $(s…

【QT表格-6】QTableWidget的currentCellChanged实现中途撤销

背景&#xff1a; 【QT表格-1】QStandardItem的堆内存释放需要单独delete&#xff0c;还是随QStandardItemModel的remove或clear自动销毁&#xff1f;-CSDN博客 【QT表格-2】QTableWidget单元格结束编辑操作endEditting_qtablewidget 单元格编辑事件-CSDN博客 【QT表格-3】Q…

做一个类似东郊到家系统都有哪些功能特点?

随着科技的发展&#xff0c;人们的生活方式也在不断变化&#xff0c;在快节奏的生活中&#xff0c;身心疲惫的人们需要一种快速有效的方式来缓解压力。同城预约上门按摩小程序就是为满足这种需求而诞生的。用户可以通过小程序&#xff0c;方便地预约按摩服务&#xff0c;无需浪…

力扣日记12.21【二叉树篇】98. 验证二叉搜索树

力扣日记&#xff1a;【二叉树篇】98. 验证二叉搜索树 日期&#xff1a;2023.12.21 参考&#xff1a;代码随想录、力扣 98. 验证二叉搜索树 题目描述 难度&#xff1a;中等 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义…

24_28-Golang函数详解

**Golang **函数详解 主讲教师&#xff1a;&#xff08;大地&#xff09; 合作网站&#xff1a;www.itying.com** **&#xff08;IT 营&#xff09; 我的专栏&#xff1a;https://www.itying.com/category-79-b0.html 1、函数定义 :::info 函数是组织好的、可重复使用的、用…

云渲染如何使用?其实很简单,只需3步就搞定了!

很多人第一次接触云渲染&#xff0c;对云渲染不了解&#xff0c;不知道云渲染怎么用&#xff0c;其实很简单&#xff0c;只需要3步就搞定了。 第一步&#xff1a;下载并安装客户端 到炫云官网下载客户端&#xff0c;下载完直接点击安装就可以&#xff0c;炫云的效果图渲染和动…

【代码规范】统一参数校验、结果返回

统一参数校验&#xff1a; 在编写Controller层的代码时&#xff0c;时常会有这种情况出现&#xff1a; RestController RequestMapping("/user") public class UserController {Resourceprivate UserService userService;PostMapping("register")public S…

【基础知识】大数据组件YARN简述

YARN是一个分布式的资源管理系统。 YARN是Hadoop系统的核心组件&#xff0c;主要功能包括负责在Hadoop集群中的资源管理&#xff0c;负责对作业进行调度运行以及监控。 ResourceManager 负责集群的资源管理与调度&#xff0c;为运行在YARN上的各种类型作业分配资源。 非HA集…

设计模式03结构型模式

结构型模式 参考网课:黑马程序员Java设计模式详解 博客笔记 https://zgtsky.top/ 结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式&#xff0c;前者采用继承机制来组织接口和类&#xff0c;后者釆用组合或聚合来组合对象。 由于…

通过讯飞 API 接口用 Vue 实现实时语音转写

通过讯飞 API 接口用 Vue 实现实时语音转写 项目地址 前言 本项目中实时语音能够转写的最大时间为 60 s&#xff0c; 这个数据也是由 API 提供方给限制掉的 为什么我会需要这个点击按钮以后能够实现实时语音的转写呢&#xff0c;因为被课程所迫&#xff0c;选了这个方向就必…

linux 性能优化-内存优化

CPU 管理一样&#xff0c;内存管理也是操作系统最核心的功能之一。内存主要用来存储系统和应 用程序的指令、数据、缓存等。 1.内存原理 1.1.内存映射 1.1.1.日常生活常说的内存是什么? 我的笔记本电脑内存就是 8GB 的这个内存其实是物理内存物理内存也称为主存&#xff0…