【算法实战】每日一题:18.2 ST 表(Sparse Table)

1.题目

给定一个长度为 n 的数列和 m 个查询,每个查询指定一个闭区间,要求对每个查询输出该区间内的最小值。

2.思路

其实用Python的话,我们可以直接用Python内置的min函数做,但是这种方法很容易超时,所以我们用ST表优化

3.ST表(Sparse Table)

1. 概述

ST 表是一种高效的静态区间查询数据结构,主要用于解决静态 RMQ(Range Minimum Query,区间最小值查询)和 RMQ 的变种问题。ST 表的优点在于预处理时间为 (O(n \log n)),查询时间为 (O(1))。但是,它不支持动态更新,只适用于静态数据。

2. 基本原理

ST 表利用了倍增思想,将查询范围的长度化为 (2^k) 的形式。任何区间都可以表示为两个重叠的 (2^k) 的区间,这样可以利用预处理的数据快速得到结果。

3. 构建 ST 表

预处理步骤
  1. 初始化数组:创建一个二维数组 st,其中 st[i][j] 表示从 i 开始长度为 (2^j) 的区间的最小值。

  2. 填充初始值:对于长度为 1 的区间,直接填充原数组的值:
    image-20240609220627543

  3. 递推填充:对于长度为 (2^j) 的区间,通过长度为 (2^{j-1}) 的区间递推得到:
    image-20240609220635975

代码实现
import math

def build_st(arr):
    # 元素个数
    n = len(arr)
    # 这里是深度
    k = int(math.log2(n)) + 1
    
    # n重循环,最后形成树,当然这里每个都是0
    st = [[0] * k for _ in range(n)]

    # 初始化长度为 1 的区间
    for i in range(n):
        # 从i开始的长度为0的,实际上就是自己
        st[i][0] = arr[i]

    # 递推填充
    j = 1
    '''
    这里一种巧妙的方法,(1 << j) 对于数字1二进制左移j位,相当于增加2的幂次
    (1 << 1) 等于 2
    (1 << 2) 等于 4
    (1 << 3) 等于 8
    '''
    # 当前的层级小于等于数组元素的总个数(纵向)
    while (1 << j) <= n:
        i = 0
        # 当前层级(横向)
        while (i + (1 << j) - 1) < n:
            st[i][j] = min(st[i][j-1], st[i + (1 << (j-1))][j-1])
            i += 1
        j += 1

    return st

这里本质上是一个树形(每次划分都是幂次的)的二维矩阵,构建是ST表,主要是为了查询方便

4. 查询 ST 表

利用 ST 表进行查询时,可以将任意区间 [L, R] 分解为两个重叠的 (2^k) 区间,并利用预处理好的最小值快速得到结果。

查询步骤
  1. 确定 k 值:计算image-20240609222027819

  2. 利用 ST 表查询:查询结果为:
    image-20240609222039635

代码实现
def query_st(st, L, R):
    j = int(math.log2(R - L + 1))
    return min(st[L][j], st[R - (1 << j) + 1][j])

5. 例子

输入
arr = [1, 3, 2, 7, 9, 11, 3, 5, 2, 6]
st = build_st(arr)
查询示例
# 查询区间 [2, 5]
print(query_st(st, 2, 5))  # 输出 2

# 查询区间 [4, 9]
print(query_st(st, 4, 9))  # 输出 2

6. 应用

  • RMQ(Range Minimum Query):快速查询数组某个区间的最小值。
  • RMQ 变种:如最大值查询、区间和查询等(通过类似的构建和查询方法实现)。

7. 优缺点

优点
  • 查询速度快:预处理后查询时间为 (O(1))。
  • 实现简单:基于数组实现,代码简洁明了。
  • 适用性广:可用于各种静态区间查询问题。
缺点
  • 预处理时间和空间复杂度较高:预处理时间和空间复杂度均为 O(n log n)
  • 不支持动态更新:只能处理静态数据,无法处理动态插入、删除和更新操作。

8. 变种

  • 最大值查询(Range Maximum Query):构建 ST 表时取最大值即可。
  • 区间和查询(Range Sum Query):利用 ST 表存储区间和,构建和查询方法类似。
  • 其他区间统计:可以根据具体需求调整构建和查询方法。
特点数组实现树实现
数据结构简单的数组
查找操作直接返回数组值,(O(1))使用路径压缩,接近 (O(1))
合并操作遍历数组更新代表元,(O(n))按秩合并,接近 (O(1))
路径压缩有,减少树的高度
实现复杂度简单稍微复杂,需要维护树结构
适用场景小规模数据大规模数据,动态连通性问题

总结

  • 数组实现:适合于小规模数据集,简单直观,但操作效率较低。
  • 树实现:适合于大规模数据集,特别是在需要频繁查找和合并操作时,效率更高。

4. 解决方案

import math

def build_st(arr):
    n = len(arr)
    k = int(math.log2(n)) + 1
    st = [[0] * k for _ in range(n)]

    # 初始化长度为 1 的区间
    for i in range(n):
        st[i][0] = arr[i]

    # 递推填充
    j = 1
    while (1 << j) <= n:
        i = 0
        while (i + (1 << j) - 1) < n:
            st[i][j] = min(st[i][j-1], st[i + (1 << (j-1))][j-1])
            i += 1
        j += 1

    return st

def query_st(st, L, R):
    j = int(math.log2(R - L + 1))
    return min(st[L][j], st[R - (1 << j) + 1][j])

def solve(n, m, arr, queries):
    # 构建 ST 表
    st = build_st(arr)

    # 处理查询
    results = []
    for L, R in queries:
        results.append(query_st(st, L, R))

    return results

# 输入处理
def main():
    import sys
    input = sys.stdin.read
    data = input().split()

    n = int(data[0])
    m = int(data[1])
    arr = list(map(int, data[2:n+2]))
    queries = []
    for i in range(m):
        L = int(data[n+2 + 2*i]) - 1  # 转换为0索引
        R = int(data[n+2 + 2*i + 1]) - 1  # 转换为0索引
        queries.append((L, R))

    # 计算并输出结果
    results = solve(n, m, arr, queries)
    for result in results:
        print(result)

if __name__ == "__main__":
    main()


主要是构建开销大,查询的话倒是比较方便

END

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

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

相关文章

OpenGauss数据库-8.权限管理

第2关&#xff1a;权限设置 gsql -d postgres -U gaussdb -W passwd123123 CREATE ROLE lily WITH CREATEDB PASSWORD passwd123123; GRANT lily TO gaussdb; 第3关&#xff1a;管理员 gsql -d postgres -U gaussdb -W passwd123123 CREATE USER peter WITH SYSADMIN PASSWOR…

【ai】openai-quickstart 配置pycharm工程

之前都是本地执行脚本【AI】指定python3.10安装Jupyter Lab环境为:C:\Users\zhangbin\AppData\Local\Programs\Python\Python310 参考之前创建的python工程 使用的是局部的私有的虚拟环境 pycharm给出的解释器 直接使用现有的,不new了 可以选择3.10 :可以选虚拟的:

macOS Sequoia 将 Mac 生产力与智能化提升至全新高度 (macOS 15 ISO、IPSW、PKG 下载)

macOS Sequoia 将 Mac 生产力与智能化提升至全新高度 (macOS 15 ISO、IPSW、PKG 下载) iPhone 镜像、Safari 浏览器重大更新、备受瞩目的游戏和 Apple Intelligence 等众多全新功能令 Mac 使用体验再升级 请访问原文链接&#xff1a;https://sysin.org/blog/macOS-Sequoia/&a…

windows上修改Podman的镜像配置源加速

目录 前言解决办法1. 打开window的Powershell 2. 修改registries.conf3. 重启podman即可 扩展内容1. 国内镜像源地址2. 阿里加速地址 前言 今天在电脑上准备通过podman安装mysql&#xff0c;结果执行安装命令后&#xff0c;网络不通没法下载镜像。 解决办法 将默认镜像源修改…

Fegin如何传参form-data文件

Form-data传输file参数&#xff0c;这个大家都比较清楚&#xff0c;那么针对于Fegin参数file参数该如何操作呢&#xff01;下面截图来找到对应的参数关系。 一、之前我们在postMan中是这种传参的&#xff0c;那么如果使用Feigin来传输文件File 二、在Fegin中传form-data参数&a…

滴滴出行 大数据研发实习生【继任】

大数据研发实习生JD 职位描述 1、负责滴滴核心业务的数据建设&#xff0c;设计并打造适应滴滴一站式出行平台业务特点的数仓体系。 2、负责抽象核心业务流程&#xff0c;沉淀业务通用分析框架&#xff0c;开发数仓中间层和数据应用产品。 3、负责不断完善数据治理体系&#xff…

湖仓一体全面开启实时化时代

摘要&#xff1a;本文整理自阿里云开源大数据平台负责人王峰&#xff08;莫问&#xff09;老师在5月16日 Streaming Lakehouse Meetup Online 上的分享&#xff0c;主要介绍在新一代湖仓架构上如何进行实时化大数据分析。内容主要分为以下五个部分&#xff1a; 1. Data Lake …

如何在ElementTree文本中嵌入标签

在 ElementTree 中&#xff0c;你可以使用 Element 对象的方法来创建新的标签&#xff0c;并将其嵌入到现有的 XML 结构中。下面是一个简单的示例&#xff0c;演示了如何在 ElementTree 文本中嵌入新的标签&#xff1a; 1、问题背景 我正在使用Python ElementTree模块来处理HT…

给Windows软件添加异常捕获模块生成dump文件(附源码)

软件在运行过程中会时常发生内存越界、内存访问为例、stack overflow线程栈溢出、空指针与野指针等异常崩溃,仅仅是依靠Debug和Release下的调试是远远不够的,因为有些崩溃不是必现的,或者是Debug下很难出现的。所以我们需要在软件中添加异常捕获的模块,在捕获到异常时生成包…

Android面试题之Java 泛型和Kotlin泛型

本文首发于公众号“AntDream”&#xff0c;欢迎微信搜索“AntDream”或扫描文章底部二维码关注&#xff0c;和我一起每天进步一点点 定义&#xff1a;JDK5引入的一种参数化类型特性 继承和实现接口可以多个 static class A{} static interface B{} static interface C{}//类必…

uniapp上传头像并裁剪图片

第一步写上uniapp自带的选择图片button按钮 点击之后会弹出选择图片的方式 拍照或从相册选择图片后将会跳到图片裁剪 然后我们裁剪完之后点击确定在上传图片 这里是上传图片的接口 拿到本地图片 上传的话自己想以那种方式上传都可以

《Brave New Words 》5.4 AI 作为“守护天使”

Part V: Keeping Kids Safe 第五部分&#xff1a;确保孩子安全 AI as “Guardian Angel” AI 作为“守护天使” The internet is a useful but scary place, even for adults. In the late 1990s, we were all blown away by the power to search across billions of pages for…

中间件复习之-分布式存储系统

单机存储系统介绍 存储引擎&#xff1a;存储系统的发动机&#xff0c;提供数据的增、删、改、查能力&#xff0c;直接决定存储系统的功能&#xff08;支持怎么样的查询&#xff0c;锁能锁到什么程度&#xff09;和性能&#xff08;增删改查速度&#xff09;。 性能因素 写入方…

sqlserver修改表结构时,报不允许保存更改。

下面是截图&#xff1a; 解决如下&#xff1a; 1&#xff09;工具--选项 2、将【阻止保存要求重新创建表的更改】前的勾选去掉。 3、点击【确定】完成。 这样我们就可以修改表结构了。

Java学习-Comparable和Comparator

Comparable和Comparator都是来做排序 Comparable自然排序 此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序&#xff0c;类的 compareTo 方法被称为它的自然比较方法。实现此接口的对象列表&#xff08;和数组&#xff09;可以通过 Collections.so…

(学习笔记)数据基建-数据安全

&#xff08;学习笔记&#xff09;数据基建-数据安全 数据安全数据安全实施难点数据安全保障流程数据安全措施实施阶段数据安全如何量化产出数据安全思考 数据安全 数据安全问题是最近比较热的话题&#xff0c;数据泄漏引发的用户信任危机事件也比比皆是&#xff0c;以及跨部门…

ThinkBook 16 2024 Ubuntu 触控板问题解决

sudo insmod goodix-gt7868q.ko sudo cp local-overrides.quirks /etc/libinput/local-overrides.quirks sudo systemctl restart gdm 有偿解决&#xff0c;无效退款

PostgreSQL17新特性之分区拆分与合并

PostgreSQL 17 带来了许多新特性和改进&#xff0c;其中之一就是对分区拆分与合并的支持。这些特性使得管理大规模数据库中的数据变得更加灵活和高效。 分区拆分 分区拆分&#xff08;Partition Split&#xff09;允许你将一个现有的分区分成多个子分区。这在需要将已有的大分…

【WEB前端2024】3D智体编程:乔布斯3D纪念馆-第38课-密室逃脱-3D互动剧情

【WEB前端2024】3D智体编程&#xff1a;乔布斯3D纪念馆-第38课-密室逃脱 使用dtns.network德塔世界&#xff08;开源的智体世界引擎&#xff09;&#xff0c;策划和设计《乔布斯超大型的开源3D纪念馆》的系列教程。dtns.network是一款主要由JavaScript编写的智体世界引擎&…

数字雕刻技术在AI绘画中的革新作用

随着人工智能技术的不断进步&#xff0c;AI在艺术领域的应用也日益广泛&#xff0c;尤其是在绘画领域。数字雕刻技术作为一种先进的图形处理方式&#xff0c;其在AI绘画中的作用不可小觑。本文将深入探讨数字雕刻技术如何推动AI绘画的发展&#xff0c;并展示这一技术在艺术创作…