我想找到某个范围内的最低值。
我每次都必须迭代数组还是有任何动态方法?
假设我有输入数组:
index: 0 1 2 3 4 5 6 7
value: 1 4 6 1 6 7 2 3
然后我必须在 < a,b > (包括)范围内选择最小的。例如:
min(0,7) = 1
min(0,2) = 1
min(4,6) = 2
min(1,2) = 4
我对最快的解决方案感兴趣,最好在恒定时间内获得结果。
同时不会更改数组。
如果您要对同一组数字执行多个查询,那么您将需要构造一个笛卡尔树。
笛卡尔树可以用作范围最小查询的有效数据结构的一部分,范围搜索问题涉及在原始序列的连续子序列中要求最小值的查询。
正如文章所说,查询可以在恒定时间内执行。
您可以对这个问题使用分段树。这是关于分段树和范围最小查询的最佳教程之一。
我正在提供 JAVA 实现,代码是不言自明的,如果您有任何疑问,请告诉我。
public class SegmentTree {
private int[] array;
private int length;
public static SegmentTree initialize(int[] a) {
return new SegmentTree(a);
}
private SegmentTree(int[] a) {
length = a.length - 1;
int l = (int) (Math.log(a.length) / Math.log(2));
l = (int) (Math.pow(2, l + 1) * 2 - 1);
array = new int[l];
initialize(a, 0, a.length - 1, 0);
}
private int initialize(int[] a, int p, int r, int index) {
if (p == r) {
array[index] = a[p];
return a[p];
}
int q = p + (r - p) / 2;
array[index] = Math.min(initialize(a, p, q, 2 * index + 1), initialize(a, q + 1, r, 2 * index + 2));
return array[index];
}
public int findMin(int p, int r) {
return _findMin(p, r, 0, length, 0);
}
private int _findMin(int qs, int qe, int ss, int se, int i) {
if (qs <= ss && se <= qe) {
return array[i];
}
if (qs > se || qe < ss) {
return Integer.MAX_VALUE;
}
int q = ss + (se - ss) / 2;
return Math.min(_findMin(qs, qe, ss, q, 2 * i + 1), _findMin(qs, qe, q + 1, se, 2 * i + 2));
}
private void print() {
int index = 0;
for (int k : array) {
System.out.println(index + ":" + k);
index++;
}
}
public static void main(String[] args) {
int[] a = {1, 34, 5, 6, 78, 5, 67, 89};
SegmentTree s = initialize(a);
System.out.println(s.findMin(2, 4));
}
}
您可以尝试以下方法(不确定我是否遗漏了什么)
如果允许您进行一些预处理,那么您可以拥有一组局部最小值(山谷)。
该数组应根据各自的索引进行排序。
获得间隔后,对最小值数组中的较低索引执行二进制搜索。选择该数组中较大的一个。说 I1
然后对最小值数组中较高的给定索引执行二进制搜索。选择该数组中较小的那个。说I2
如果 I2 >= I1,则区间中至少存在一个局部最小值。只需比较该区间内的最小值和边界处的值即可得到答案。
否则,区间内不存在局部最小值。在这种情况下,最小值应位于区间的边界。只需比较两个值并获得较低的值。
这是一项标准任务。您可以使用标准库功能。它应该是最快的。这里的例子:
#include <iostream> // std::cout
#include <algorithm> // std::min_element, std::max_element
int main () {
int myints[] = {3,7,2,5,6,4,9};
std::cout << "The smallest element is " << *std::min_element(myints,myints+7) << '\n';
return 0;
}
PS 你不能在恒定时间内得到结果,因为如果你需要 N 个元素之间的最小值,你需要检查每个元素。最小任务复杂度为 O(N)。