当前位置: 首页 > article >正文

线段树 算法

文章目录

  • 基础知识
      • 适用场景
      • 小结
  • 题目概述
  • 题目详解
    • 300.最长递增子序列
    • 2407.最长递增子序列 II

基础知识

线段树和树状数组都只是一个工具来的,题目并不会一下子就告诉你这个题目用到线段树和树状数组,这个取决于你想使用的数据结构以及所要优化的方向

线段树和树状数组(也称为二叉索引树)是两种常用的数据结构,主要用于处理数组的区间查询和更新操作。它们的主要区别如下:

适用场景

  • 线段树
    • 适用于需要复杂区间操作的场景,如区间最大值、区间最小值、区间更新等。
    • 适合动态性较强的问题。
# 点的更新
class Tree:
    
    def __init__(self,n):
        self.st = [0]*(4*n)
    
    def update(self,o,l,r,index,val):
        # l,r 是当前区间的范围,index 是要插入的数据的索引
        if l==r:
            self.st[o] = val
            return 
        mid = (l+r)//2
        if index<=mid:
            self.update(2*o,l,mid,index,val)
        else:
            self.update(2*o+1,mid+1,r,index,val)
        self.st[o] = max(self.st[2*o],self.st[2*o+1])
    
    def query(self,o,l,r,L,R):
        if l >= L and r <= R:
            return self.st[o]
        mid = (l+r)//2
        res = 0
        if L<=mid:
            res = max(res,self.query(2*o,l,mid,L,R))
        if R > mid:
            res = max(res,self.query(2*o+1,mid+1,r,L,R))
        return res


  • 树状数组
    • 适用于简单的前缀和查询和单点更新问题。
    • 适合静态或半静态问题,且代码实现更简洁。

小结

特性线段树树状数组
结构二叉树基于数组的树形结构
功能支持复杂区间操作主要用于前缀和查询
时间复杂度 ( O ( log ⁡ n ) (O(\log n) (O(logn)) ( O ( log ⁡ n ) ) (O(\log n)) (O(logn))
空间复杂度 ( O ( 4 n ) (O(4n) (O(4n)) ( O ( n ) ) (O(n)) (O(n))
适用场景动态区间操作简单查询和更新

题目概述

2407.最长递增子序列 II

题目详解

300.最长递增子序列

这个题目是方便我们做下面的 最长递增子序列

在这里插入图片描述

思路分析:这个最长递增子序列,我们采用动态规划进行求解,
dp[i]的定义:以nums[i]为结尾的子序列的最长的长度
有递推公式:
d p [ i ] = m a x ( d p [ i ] , d p [ j ] + 1 ) dp[i] = max(dp[i],dp[j]+1) dp[i]=max(dp[i],dp[j]+1),当我们遍历前 i − 1 i-1 i1个元素,当满足 n u m s [ j ] < = n u m s [ i ] nums[j]<=nums[i] nums[j]<=nums[i]的时候更新
时间复杂度分析:是o(n^2)

2407.最长递增子序列 II

在这里插入图片描述
在这里插入图片描述

思路分析:这个题目首先想到可以使用动态规划,但是如果内层的的判断i之前的满足的情况的时候还是使用暴力进行求解的话,就会出现超时的情况,所以我们就得考虑使用线段树,线段树对于求解区间的最值的时间复杂度只有o(logn)

class Solution:
    def lengthOfLIS(self, nums: List[int], k: int) -> int:
        ans = 1
        
        # dp[i][j] 表示前i个元素中,以值j结尾的长度的子序列长度的最大值
        # 注意,这里的j是值域
        tr = Tree(100005)
        # 这个求解的是外层循环i
        for va in nums:
            if va != 1:
            	# 确保这个zuo没有超过范围
                zuo = max(1,va-k)
                you = va-1
                # 1为根节点
                # 这个是求解的内层循环j
                pre = tr.query(1,1,100000,zuo,you)
                now = pre+1
                ans = max(ans,now)
                tr.update(1,1,100000,va,now)
            else:
                tr.update(1,1,100000,1,1)
        return ans

# 线段树模版
class Tree:

    def __init__(self,n):
        self.t = [0] * (n*4)
    def update(self,o,l,r,index,va):
        if l==r:
            self.t[o] = va
            return 
        m = (l+r) //2
        if index<=m:
            self.update(o*2,l,m,index,va)
        else:
            self.update(o*2+1,m+1,r,index,va)
        self.t[o] = max(self.t[o*2],self.t[o*2+1])

    def query(self,o,l,r,L,R):
        if l>=L and r<= R:
            return self.t[o]
        m = (l+r) // 2
        res = 0
        if m >= L:
            res = max(res,self.query(o*2,l,m,L,R))
        if R>m:
            res = max(res,self.query(o*2+1,m+1,r,L,R))
        return res


http://www.kler.cn/a/524467.html

相关文章:

  • SpringBoot中@Valid与@Validated使用场景详解
  • mac安装dockerdesktop优化
  • 园区管理智能化创新引领企业效能提升与风险控制新趋势
  • JVM--类加载器
  • NPM 使用介绍
  • 使用 Redis List 和 Pub/Sub 实现简单的消息队列
  • PA1记录
  • TiDB 常用命令
  • Java---入门基础篇(上)
  • vue-有关于TS与路由器
  • android wifi 热点名称的默认配置
  • 企业SaaS(软件即服务)行业中AARRR
  • 搭建Spark分布式集群
  • 学习数据结构(2)空间复杂度+顺序表
  • 昆仑万维Java开发面试题及参考答案
  • 【linux三剑客】grep练习题
  • PETSc源码分析: Optimization Solvers
  • VLC-Qt: Qt + libVLC 的开源库
  • 小白一命速通JS中的windowglobal对象
  • Prompt提示词完整案例:让chatGPT成为“书单推荐”的高手
  • Spring项目部署到Docker
  • C# 9.0记录类型:解锁开发效率的魔法密码
  • 17、智能驾驶硬件架构安全设计一般原则
  • Linux学习笔记——用户管理
  • 【回溯+剪枝】找出所有子集的异或总和再求和 全排列Ⅱ
  • JUC--ConcurrentHashMap底层原理