You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过预计算以亚线性时间统计数组中含k的相邻元素区间数?

没问题,我来帮你梳理这个问题,然后给出几种能支持亚线性时间查询的预计算方案,都是高层思路,不用纠结具体代码细节:

问题核心先理清楚

咱们先把问题拆解明白:给定n个元素的数组A,我们有n-1个相邻元素对(对应索引i从0到n-2),每个i对应一个区间[L_i, R_i]——其中L_i = min(A[i], A[i+1]),R_i = max(A[i], A[i+1])。每次查询会给你三个值a、b、k,需要统计i在[a, b-1]范围内的所有i中,满足L_i ≤ k ≤ R_i的数量。目标是通过预计算,让每次查询的时间复杂度低于线性(也就是亚线性,比如O((log n)²)这种级别)。

方案1:线段树+二分查找(在线查询首选)

这个方案适合在线场景(查询是随时来的,不能提前知道所有查询),核心是用线段树存储每个区间的预处理信息,再用二分快速统计:

  • 预处理阶段:
    1. 建一棵线段树,每个叶子节点对应一个i(0到n-2),存储该i的L_i和R_i。
    2. 对于线段树的每个内部节点,收集它覆盖的所有i的(L_i, R_i)对,然后按L_i从小到大排序,得到两个数组:sorted_L(排序后的L值)和对应的sorted_R(和sorted_L一一对应的R值)。
    3. 对每个内部节点的sorted_R数组,提前把每个前缀(比如前1个、前2个…前m个元素,m是该节点覆盖的i的数量)都排序好,这样之后可以快速统计前缀中≥k的元素数量。
  • 查询阶段:
    1. 把查询的i范围[a, b-1]拆成线段树里的O(log n)个不重叠节点(这是线段树的常规操作)。
    2. 对每个拆分出来的节点:
      • 用二分查找在sorted_L里找到最大的索引j,使得sorted_L[j] ≤ k——如果找不到,说明这个节点里没有符合条件的i,直接跳过。
      • 拿这个j值,去查对应的sorted_R前缀的排序数组,用二分找到第一个≥k的元素位置,用j+1减去这个位置,就是这个节点里符合条件的i的数量。
    3. 把所有节点的统计结果加起来,就是最终答案。
  • 复杂度说明:预处理时间是O(n (log n)²),每次查询时间是O((log n)²),完全符合亚线性的要求。
方案2:二维线段树(适合k的取值范围很大的场景)

如果k的取值范围特别大(比如A里的元素是1e9级别的),可以先用坐标压缩把所有涉及的k值(包括所有L_i、R_i和查询的k)映射到一个连续的小范围,然后用二维线段树来处理:

  • 预处理阶段:
    1. 建一棵外层线段树,每个节点对应一段k的范围。外层的每个节点内部,再建一棵内层线段树,内层线段树的节点对应i的位置(0到n-2),支持单点加1和区间求和操作。
    2. 对每个i,我们要在外层线段树的[L_i, R_i]区间内,给内层线段树的i位置加1——这相当于给所有覆盖[L_i, R_i]的外层节点,都执行一次内层线段树的单点更新。
  • 查询阶段:
    1. 在外层线段树里找到对应k值的节点(或者拆分出覆盖k的几个节点)。
    2. 在这些节点的内层线段树里,查询[a, b-1]区间的总和,这个总和就是符合条件的i的数量。
  • 复杂度说明:预处理时间是O(n log M log n)(M是压缩后的k范围),查询时间是O(log M log n),也是亚线性的。
方案3:离线查询+前缀和(适合批量查询场景)

如果所有查询都是提前已知的(离线场景),这个方案会更简单高效:

  • 预处理+查询阶段:
    1. 收集所有的查询,还有所有i对应的[L_i, R_i],把所有涉及的k值(L_i、R_i、查询的k)都收集起来,排序去重,给每个k分配一个压缩后的索引(这样能把大的k范围缩小)。
    2. 对每个i,生成两个事件:当k等于L_i时,给i位置加1;当k等于R_i + 1时,给i位置减1。
    3. 把所有事件按k值从小到大排序,同时把所有查询也按k值从小到大排序。
    4. 维护一个前缀和数组prefix(初始全0),然后按k的顺序依次处理事件和查询:
      • 先处理当前k对应的所有事件:如果是加1事件,就给prefix[i] +=1;如果是减1事件,就给prefix[i] -=1。
      • 再处理当前k对应的所有查询:计算prefix[b-1] - (prefix[a-1] if a>0 else 0),这个结果就是该查询的答案。
  • 复杂度说明:整体时间是O((n + Q) log(n+Q))(Q是查询数量),每个查询的处理是O(1),批量处理效率很高,也是亚线性的。
用示例验证一下

拿你给的示例:数组是[6,3,2,8,5],a=1,b=3,k=3。

  • 相邻元素对的i范围是0-3:
    • i=0:L=3,R=6
    • i=1:L=2,R=3
    • i=2:L=2,R=8
    • i=3:L=5,R=8
  • 查询的i范围是1-2,用方案1的话,线段树里覆盖i=1-2的节点的sorted_L是[2,2],sorted_R是[3,8]。查询时,二分sorted_L找到≤3的最大j是1,然后在前2个sorted_R元素里统计≥3的数量,两个都符合,所以结果是2,和示例一致。

内容的提问来源于stack exchange,提问作者pokemon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 20:37:45