数据结构和算法:范围查询和范围和查询
数据结构和算法:范围查询和范围和查询
问题描述
假设 A[1..n] 是一个存储 n 个可能不相异数的数组。
(a) 范围查询
范围查询指定两个整数 x 和 y,它们构成一个区间 (x, y)。范围查询的答案是 A 中大于 x 且小于或等于 y 的元素数量。没有要求 x 和 y 是 A 的元素。
例如,如果 A = [4, 5, 2, 6, 8, 3, 4, 4],区间 (3, 6] 的范围查询会返回 5,因为 A 中有五个元素在 (3, 6) 中,即 A[1], A[2], A[4], A[7] 和 A[8]。类似地,区间 (7, 10) 的范围查询将返回 1。
算法
为了回答范围查询,我们可以使用一个数据结构 C,它是一个有序的集合,其中包含 A 中的所有元素。我们可以使用一个平衡二叉搜索树 (BST) 来实现 C,例如红黑树或 AVL 树。
构建 C 的算法如下:
- 创建一个空的 BST C。
- 遍历数组 A,对于每个元素 a,将其插入 C 中。
这个算法的运行时间是 O(NlogN),因为插入一个元素到 BST 中的时间复杂度是 O(logN),而插入 N 个元素的总时间复杂度是 O(NlogN)。
为了回答一个范围查询,我们可以使用 C 的搜索操作。搜索操作在 BST 中需要 O(logN) 时间,因此回答一个范围查询需要 O(logN) 时间。
伪代码
# 构建数据结构 C
def buildC(A):
C = BST() # 创建一个空的 BST
for i in range(1, n + 1):
C.insert(A[i]) # 将数组中的每个元素插入 BST
return C
# 范围查询
def rangeQuery(C, x, y):
count = 0
for a in C: # 遍历 BST 中的每个元素
if x < a <= y: # 检查元素是否在给定范围内
count += 1
return count
(b) 范围和查询
假设 A[1..n] 中的数字来自给定的某个正整数 k 的范围 (1, k]。范围和查询指定范围 [1, k] 中的两个整数 x 和 y,它们构成一个区间 (x, y)。范围和查询的答案是 A 中大于 x 且小于或等于 y 的元素之和。
例如,如果 k = 9 并且 A = [4, 5, 2, 6, 8, 3, 4, 4],对于区间 (3, 6) 的范围和查询将返回 23。区间 (7, 10) 不定义范围和查询,因为 10 在范围 [1, 9] 之外。
算法
为了回答范围和查询,我们可以使用一个前缀和数组 P,其中 P[i] 表示 A 中前 i 个元素的和。我们可以使用 P 来回答任何范围和查询。
构建 P 的算法如下:
- 创建一个大小为 n+1 的数组 P,初始值都为 0。
- 遍历数组 A,对于每个元素 A[i],更新 P[i+1] = P[i] + A[i]。
这个算法的运行时间是 O(N),因为更新 P 的每个元素需要常数时间,总共需要更新 n+1 个元素。
为了回答一个范围和查询,我们可以使用 P 数组的差值。我们可以通过计算 P[y] - P[x] 来得到 A 中 x 到 y 之间的元素之和。
伪代码
# 构建前缀和数组 P
def buildP(A):
n = len(A)
P = [0] * (n + 1) # 创建一个大小为 n+1 的数组,初始化为 0
for i in range(1, n + 1):
P[i] = P[i - 1] + A[i - 1] # 计算前缀和
return P
# 范围和查询
def rangeSumQuery(P, x, y):
return P[y] - P[x] # 使用前缀和数组计算范围内的元素之和
由于 P 数组的构建只需要 O(N) 时间,而范围和查询只需要一次减法操作,因此一个范围和查询可以在 O(1) 时间内回答。
原文地址: https://www.cveoy.top/t/topic/4jA 著作权归作者所有。请勿转载和采集!