Python算法题集_二叉搜索树中第K小的元素

 Python算法题集_二叉搜索树中第K小的元素

  • 题230:二叉搜索树中第K小的元素
  • 1. 示例说明
  • 2. 题目解析
    • - 题意分解
    • - 优化思路
    • - 测量工具
  • 3. 代码展开
    • 1) 标准求解【DFS递归+终止检测】
    • 2) 改进版一【BFS迭代+终止检测】
    • 3) 改进版二【BFS迭代+终止检测+计数定位】
    • 4) 改进版三【BFS迭代+终止检测+计数定位+高速双向队列】
  • 4. 最优算法
  • 5. 进阶算法

本文为Python算法题集之一的代码示例

题230:二叉搜索树中第K小的元素

1. 示例说明

  • 给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 1 开始计数)。

    示例 1:

    img

    输入:root = [3,1,4,null,2], k = 1
    输出:1
    

    示例 2:

    在这里插入图片描述

    输入:root = [5,3,6,2,4,null,null,1], k = 3
    输出:3
    

    提示:

    • 树中的节点数为 n
    • 1 <= k <= n <= 104
    • 0 <= Node.val <= 104

    **进阶:**如果二叉搜索树经常被修改(插入/删除操作)并且你需要频繁地查找第 k 小的值,你将如何优化算法?


2. 题目解析

- 题意分解

  1. 本题为在二叉搜索树中寻找第K小的值
  2. 基本的基本思路是深度优先算法【DFS(Depth-First Search)】、广度有限算法【BFS(Breadth-First Search)】

- 优化思路

  1. 通常优化:减少循环层次

  2. 通常优化:增加分支,减少计算集

  3. 通常优化:采用内置算法来提升计算速度

  4. 分析题目特点,分析最优解

    1. 通过DFS、BFS进行中序遍历,找到第K个值

    2. 可以测试高速双向队列deque的性能


- 测量工具

  • 本地化测试说明:LeetCode网站测试运行时数据波动很大,因此需要本地化测试解决这个问题
  • CheckFuncPerf(本地化函数用时和内存占用测试模块)已上传到CSDN,地址:Python算法题集_检测函数用时和内存占用的模块
  • 本题本地化超时测试用例自己生成,详见【最优算法章节】

3. 代码展开

1) 标准求解【DFS递归+终止检测】

使用DFS递归中序遍历求解,找到第K个值后返回

马马虎虎,超过64%在这里插入图片描述

import CheckFuncPerf as cfpclass Solution:def kthSmallest_base(self, root, k):def inOrder_findk(root, result, k):if root == None:returnif inOrder_findk(root.left, result, k):return Trueresult.append(root.val)if len(result) == k:return Trueif inOrder_findk(root.right, result, k):return Truereturn Falseresult = []inOrder_findk(root, result, k)return result[-1]aroot = sortedArrayToBST(nums)
aSolution = Solution()
result = cfp.getTimeMemoryStr(Solution.kthSmallest_base, aSolution, aroot, 51000)
print(result['msg'], '执行结果 = {}'.format(result['result']))# 运行结果
函数 kthSmallest_base 的运行时间为 11.97 ms;内存使用量为 756.00 KB 执行结果 = 50999

2) 改进版一【BFS迭代+终止检测】

使用BFS迭代中序遍历求解,找到第K个值后返回

天下无双,超越99%在这里插入图片描述

import CheckFuncPerf as cfpclass Solution:def kthSmallest_ext1(self, root, k):stack, result, iPos = [], [], kwhile root or stack:if root:stack.append(root)root = root.leftelse:curnode = stack.pop()iPos -= 1if iPos == 0:return curnode.valresult.append(curnode.val)root = curnode.rightaroot = sortedArrayToBST(nums)
aSolution = Solution()
result = cfp.getTimeMemoryStr(Solution.kthSmallest_ext1, aSolution, aroot, 51000)
print(result['msg'], '执行结果 = {}'.format(result['result']))# 运行结果
函数 kthSmallest_ext1 的运行时间为 9.97 ms;内存使用量为 0.00 KB 执行结果 = 50999

3) 改进版二【BFS迭代+终止检测+计数定位】

使用BFS迭代中序遍历求解,直接通过计数定位获取节点值【不生成中序遍历结果】

性能优越,超过91%在这里插入图片描述

import CheckFuncPerf as cfpclass Solution:def kthSmallest_ext2(self, root, k):stack = [root]while stack:curnode = stack.pop()while curnode:stack.append(curnode)curnode = curnode.leftcurnode = stack.pop()k-=1if k==0:return curnode.valstack.append(curnode.right)aroot = sortedArrayToBST(nums)
aSolution = Solution()
result = cfp.getTimeMemoryStr(Solution.kthSmallest_ext2, aSolution, aroot, 51000)
print(result['msg'], '执行结果 = {}'.format(result['result']))# 运行结果
函数 kthSmallest_ext2 的运行时间为 8.98 ms;内存使用量为 0.00 KB 执行结果 = 50999

4) 改进版三【BFS迭代+终止检测+计数定位+高速双向队列】

使用BFS迭代中序遍历求解,采用高速双向队列deque替换list,直接通过计数定位获取节点值【不生成中序遍历结果】

性能优良,超过83%在这里插入图片描述

import CheckFuncPerf as cfpclass Solution:def kthSmallest_ext3(self, root, k):from collections import dequestack = deque([root])while stack:curnode = stack.pop()while curnode:stack.append(curnode)curnode = curnode.leftcurnode = stack.pop()k-=1if k==0:return curnode.valstack.append(curnode.right)aroot = sortedArrayToBST(nums)
aSolution = Solution()
result = cfp.getTimeMemoryStr(Solution.kthSmallest_base, aSolution, aroot, 51000)
print(result['msg'], '执行结果 = {}'.format(result['result']))# 运行结果
函数 kthSmallest_ext3 的运行时间为 8.98 ms;内存使用量为 8.00 KB 执行结果 = 50999

4. 最优算法

根据本地日志分析,本次出现了并列的最优算法,第3种方式【BFS迭代+终止检测+计数定位】、第4种方式【BFS迭代+终止检测+计数定位+高速双向队列】kthSmallest_ext2kthSmallest_ext3速度一致,说明listdeque在某些操作上是基本等价的

iLen = 5000000
nums = [x for x in range(iLen)]
def sortedArrayToBST(nums):if not nums:returnmid = len(nums) // 2root = TreeNode(nums[mid])if mid == 0:return rootroot.left = sortedArrayToBST(nums[:mid])root.right = sortedArrayToBST(nums[mid+1:])return root
aroot = sortedArrayToBST(nums)
aSolution = Solution()
result = cfp.getTimeMemoryStr(Solution.kthSmallest_base, aSolution, aroot, 51000)
print(result['msg'], '执行结果 = {}'.format(result['result']))
result = cfp.getTimeMemoryStr(Solution.kthSmallest_ext1, aSolution, aroot, 51000)
print(result['msg'], '执行结果 = {}'.format(result['result']))
result = cfp.getTimeMemoryStr(Solution.kthSmallest_ext2, aSolution, aroot, 51000)
print(result['msg'], '执行结果 = {}'.format(result['result']))
result = cfp.getTimeMemoryStr(Solution.kthSmallest_ext3, aSolution, aroot, 51000)
print(result['msg'], '执行结果 = {}'.format(result['result']))# 算法本地速度实测比较
函数 kthSmallest_base 的运行时间为 11.97 ms;内存使用量为 756.00 KB 执行结果 = 50999
函数 kthSmallest_ext1 的运行时间为 9.97 ms;内存使用量为 0.00 KB 执行结果 = 50999
函数 kthSmallest_ext2 的运行时间为 8.98 ms;内存使用量为 0.00 KB 执行结果 = 50999
函数 kthSmallest_ext3 的运行时间为 8.98 ms;内存使用量为 8.00 KB 执行结果 = 50999

5. 进阶算法

**进阶:**如果二叉搜索树经常被修改(插入/删除操作)并且你需要频繁地查找第 k 小的值,你将如何优化算法

思路:

  1. 保存一个二叉搜索树的遍历列表和一个修改计数器【默认值为0】
  2. 发生插入/删除操作时更新计数器【+1】
  3. 查询第k小的值时检测计数器,如果计数器大于0则更新遍历列表,如果计数器等于0则直接取值
  4. 代码示意如下
class Solution:def __init__(self, root):self.imodify = 0self.list_inorder = [root]def insertnode(self, treenode):self.imodify += 1# do insert nodedef deletenode(self, treenode):self.imodify += 1# do delete nodedef refresh_inorderlist(self, root):self.list_inorder.clear()stack, tmpnode = [], rootwhile tmpnode or stack:if tmpnode:stack.append(tmpnode)tmpnode = tmpnode.leftelse:curnode = stack.pop()self.list_inorder.append(curnode.val)tmpnode = curnode.right      def kthSmallest(self, root, k):if self.imodify > 0:self.refresh_inorderlist(root)self.imodify = 0return self.list_inorder[k-1]

一日练,一日功,一日不练十日空

may the odds be ever in your favor ~

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

海外大带宽服务器连接失败:原因与解决策略

​随着全球互联网的发展&#xff0c;越来越多的企业和个人选择使用海外大带宽服务器来满足数据传输和业务需求。然而&#xff0c;在实际使用中&#xff0c;有时会出现服务器连接失败的问题。本文将为您分析原因并提供相应的解决策略。 一、海外大带宽服务器连接失败的原因 网络…

纯前端低代码平台demo,vue框架,nodejs,简单的pm2纯前端部署实践

文章目录 目录结构说明本地运行项目启动后的页面demo前端部署打包pm2nginx 后话 前段时间开发了一个纯前端的低代码平台demo&#xff0c;vue框架&#xff0c;nodejs&#xff0c;pm2纯前端部署实践。为此记录一下开发过程以及各方面遇到的问题&#xff0c;并作说明。 表单用了若…

javaweb学习day03(JS+DOM)

一、javascript入门 1 官方文档 地址: https://www.w3school.com.cn/js/index.asp离线文档: W3School 离线手册(2017.03.11 版).chm 2 基本说明 JavaScript 能改变 HTML 内容&#xff0c;能改变 HTML 属性&#xff0c;能改变 HTML 样式 (CSS)&#xff0c;能完成 页面的数据…

Python中 ‘==‘ 与‘is‘的区别

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 比较判断逻辑是在代码中经常使用的&#xff0c;在Python中常用 ‘’ 和 is 来做比较判断。 : 双等号是用来比较变量所指向内存单元中的值是否相等&#xff0c;它只关心值&#xff0c;并不在意值的内存地址&#xff0c;也就是说…

剖析中青年专家英年早逝现象

剖析中青年专家英年早逝现象 近年来&#xff0c;一个令人痛心的现象频繁触动公众的心弦——不少处于事业巅峰期的中青年专家、教授不幸英年早逝。他们的去世不仅是个人和家庭的悲剧&#xff0c;也是国家和社会的巨大损失。这一现象背后的原因错综复杂&#xff0c;涉及工作压力、…

《辽宁春晚》开场动画惊艳亮相,蓝海创意云渲染服务再显神通

随着2024年甲辰龙年的脚步日益临近&#xff0c;备受瞩目的《辽宁春晚》于除夕夜为全国观众带来了一场精彩绝伦的视听盛宴。作为整场晚会的亮点之一&#xff0c;开场动画以其独特的创意和精美的画面效果&#xff0c;为观众带来了一个难忘的视觉体验。而这一精彩的呈现&#xff0…

无人机技术,无人机动力系统知识,电机、电调、桨叶技术详解

无人机动力系统中的电机、电调和桨叶技术都是非常重要的部分&#xff0c;以下是对这些技术的详解&#xff1a; 无人机电机 在无人机动力系统中&#xff0c;电机是将电能转化为机械能的关键部件。其主要作用是产生旋转力矩&#xff0c;驱动螺旋桨的旋转&#xff0c;从而实现无…

UnityShader——07数学知识:向量

数学知识&#xff1a;向量 二维&#xff08;笛卡尔&#xff09;坐标系 二维向量&#xff08;矢量&#xff09; 具有方向的线段叫做有向线段&#xff0c;以A为起点、B为终点的有向线段作为向量&#xff0c;可以记作 v B - A。区别于有向线段&#xff0c;在一般的数学研究中&a…

Shell脚本条件语句

1.条件测试 文件测试与整数测试 test命令 测试表达式是否成立&#xff0c;若成立返回0&#xff0c;不成立返回其他数值 格式1&#xff1a;test 条件表达式 格式2&#xff1a;[ 条件表达式 ] 测试 是否成功使用 $? 操作符&#xff1a; -d&#xff1a;测试是否为目…

【Java程序员面试专栏 Java领域】Java虚拟机 核心面试指引

关于Java 虚拟机部分的核心知识进行一网打尽,主要包括Java虚拟机的内存分区,执行流程等,通过一篇文章串联面试重点,并且帮助加强日常基础知识的理解,全局思维导图如下所示 JVM 程序执行流程 包括Java程序的完整执行流程,以及Javac编译,JIT即时编译 Java程序的完整执…

九宫格锁屏模块,九宫格设置密码

要使用九宫格设置密码,先用自定义一个九宫格样式,使用的自定义的view画出九个点,然后重写onMeasure和onDraw,这两个方法,并处理onTouchEvent,这个事件 在Android视图的绘制和布局过程中&#xff0c;onMeasure和onDraw这两个方法的调用顺序是固定的。以下是它们通常的调用顺序&…

成都力寰璨泓科技有限公司抖音小店购物新体验

在数字化时代&#xff0c;网购已成为人们生活中不可或缺的一部分。随着抖音等短视频平台的兴起&#xff0c;越来越多的消费者选择在抖音小店购物。成都力寰璨泓科技有限公司抖音小店&#xff0c;作为新兴的电商力量&#xff0c;凭借其可靠的品质和服务&#xff0c;正逐渐成为消…