给定一个数组列表和大量的设置时间,我需要快速找到每个数组的某个子跨度中的最小值。在概念上:
class SpanThing
{
int Data;
SpanThing(int[][] data) /// must be rectangulare
{
Data = data;
//// process, can take a while
}
int[] MinsBruteForce(int from, int to)
{
int[] result = new int[data.length];
foreach(int index, int[] dat; Data)
{
result[i] = int.max;
foreach(int v; dat[from .. to]);
result[i] = min(result[i], v);
}
return result;
}
int[] MinsSmart(int from, int to)
{
// same as MinsBruteForce but faster
}
}
我目前关于如何做到这一点的想法是在数据上构建二叉树,其中每个节点包含相关跨度中的min。这样,在一行的跨度中找到min将包括仅查找构成它的树节点的min。这个集合对于每一行都是相同的,因此可以计算一次。
有没有人看到这个想法的任何问题或更好的方法?
为了澄清,我正在谈论的树将设置为sutch,根节点将包含整行的最小值,对于每个节点,它的左子节点将具有左半部分的最小值。父母的跨度和右边的相同。
0 5 6 2 7 9 4 1 7 2 8 4 2
------------------------------------------------
| 5 | 6| | 7 | 9 | | 1 | 7 | 2 | 8 | 4 | 2
0 | 5 | 2 | 7 | 4 | 1 | 2 | 2
0 | 2 | 1 | 2
0 | 1
0
此树可以映射到数组,并以这样的方式定义,即可以计算段边界,从而快速查找。
我正在优化的情况是我有一个固定的输入设置和大量的前期时间,但后来需要在各种跨度上进行许多快速测试。
答案 0 :(得分:2)
您描述的方法听起来像是在尝试进行某种memoization或缓存,但如果您反复检查相同的跨度或嵌套跨度,那只能帮助您。
min([0..n])的一般情况将是 O(n),这就是你已经拥有的。
您的代码似乎更关心数组中的实际数字而不是它们在数组中的顺序。如果你要反复检查这些跨度,是否可以先对数据进行排序,这可能是一个 O(n log n)操作,然后是一堆 O (1) ops?大多数语言都在其标准库中内置sorting algorithm。
答案 1 :(得分:2)
您提出的解决方案似乎使用恒定空间开销,恒定时间设置和查询的对数时间来给出答案。如果您愿意支付二次空间(即提前计算所有间隔),您可以在恒定时间内获得答案。您的对数方案几乎肯定是首选。
如果有可能做得更好,我不会感到惊讶,但如果有一个简单的数据结构可以做得更好,我会感到震惊 - 在实践中,对数时间几乎总是足够快。去吧。
答案 2 :(得分:0)
我们不清楚如何使用您描述的树方法有效地表示间隔的层次结构。划分间隔的方法有很多种 - 我们是否必须考虑各种可能性?
这样的简单方法是否足够:假设data
是N x M数组。我将创建一个M x M x N数组,其中条目(i,j,k)
给出data(k,i:j)
的“min”。数组条目将按需填充:
int[] getMins(int from, int to)
{
assert to >= from;
if (mins[from][to] == null)
{
mins[from][to] = new int[N];
// populate all entries (from,:,:)
for (int k = 0; k < N; k++)
{
int t = array[k][from];
for (int j = from; j < M; j++)
{
if (array[k][j] < t)
t = array[k][j];
mins[from][j][k] = t;
}
}
}
return mins[from][to];
}