6

我想找到某个范围内的最低值。
我每次都必须迭代数组还是有任何动态方法?

假设我有输入数组:

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

我对最快的解决方案感兴趣,最好在恒定时间内获得结果。

同时不会更改数组。

4

4 回答 4

8

如果您要对同一组数字执行多个查询,那么您将需要构造一个笛卡尔树

笛卡尔树可以用作范围最小查询的有效数据结构的一部分,范围搜索问题涉及在原始序列的连续子序列中要求最小值的查询。

正如文章所说,查询可以在恒定时间内执行。

于 2013-11-03T18:48:51.993 回答
1

您可以对这个问题使用分段树是关于分段树和范围最小查询的最佳教程之一。

我正在提供 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));
    }
}
于 2013-11-04T14:24:48.437 回答
0

您可以尝试以下方法(不确定我是否遗漏了什么)

如果允许您进行一些预处理,那么您可以拥有一组局部最小值(山谷)。

该数组应根据各自的索引进行排序。

获得间隔后,对最小值数组中的较低索引执行二进制搜索。选择该数组中较大的一个。说 I1

然后对最小值数组中较高的给定索引执行二进制搜索。选择该数组中较小的那个。说I2

如果 I2 >= I1,则区间中至少存在一个局部最小值。只需比较该区间内的最小值和边界处的值即可得到答案。

否则,区间内不存在局部最小值。在这种情况下,最小值应位于区间的边界。只需比较两个值并获得较低的值。

于 2013-11-03T18:49:10.733 回答
-2

这是一项标准任务。您可以使用标准库功能。它应该是最快的。这里的例子:

#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)。

于 2013-11-03T18:37:50.963 回答