我有一个3D数组,其中值是单调的。如何找到所有(x,y),| f(X,Y,Z) - v1 | <吨。
答案 0 :(得分:2)
有Omega(n ^ 2)个点,其坐标总和为n-1。关于这些点的值如何相互比较,没有任何事先知道,因此,在最坏的情况下,所有这些点都必须进行检查。通过在每个constant-z切片中运行2D算法,可以提供与常数因子匹配的上限。
答案 1 :(得分:1)
对于每个值(例如v1
),执行以下步骤:
最坏情况复杂度为O(O(2D算法)* n)。
对于多个值(v2
等),保留函数评估的缓存,并为每个值重新执行算法。对于100 ^ 3,密集阵列就足够了。
将此视为等值面提取算法可能会有用,尽管您的单调性约束使其更容易。
答案 2 :(得分:1)
如果3d数组在每个维度上单调递减,那么我们知道如果
f(x0, y0, z0) < v1 - t
or
f(x1, y1, z1) > v1 + t
那么子数组f(x0...x1, y0...y1, z0...z1)
的任何元素都不能包含任何有趣的点。要看到这一点,请考虑
f(x0, y0, z0) <= f(x, y0, z0) <= f(x, y, z0) <= f(x, y, z)
适用于子阵列的每个(x, y, z)
,并且(x1, y1, z1)
具有类似的关系(反向)。因此f(x0, y0, z0)
和f(x1, y1, z1)
分别是子数组的最小值和最大值。
然后可以使用递归细分方案实现简单的搜索方法:
template<typename T, typename CBack>
int values(Mat3<T>& data, T v0, T v1, CBack cback,
int x0, int y0, int z0, int x1, int y1, int z1) {
int count = 0;
if (x1 - x0 <= 2 && y1 - y0 <= 2 && z1 - z0 <= 2) {
// Small block (1-8 cells), just scan it
for (int x=x0; x<x1; x++) {
for (int y=y0; y<y1; y++) {
for (int z=z0; z<z1; z++) {
T v = data(x, y, z);
if (v >= v0 && v <= v1) cback(x, y, z);
count += 1;
}
}
}
} else {
T va = data(x0, y0, z0), vb = data(x1-1, y1-1, z1-1);
count += 2;
if (vb >= v0 && va <= v1) {
int x[] = {x0, (x0 + x1) >> 1, x1};
int y[] = {y0, (y0 + y1) >> 1, y1};
int z[] = {z0, (z0 + z1) >> 1, z1};
for (int ix=0; ix<2; ix++) {
for (int iy=0; iy<2; iy++) {
for (int iz=0; iz<2; iz++) {
count += values<T, CBack>(data, v0, v1, cback,
x[ix], y[iy], z[iz],
x[ix+1], y[iy+1], z[iz+1]);
}
}
}
}
}
return count;
}
代码基本上接受一个子数组,如果最低元素太大或者最高元素太小,则简单地跳过搜索,否则将数组拆分为8个子多维数据集。当子阵列很小(2x2x2或更小)并且在这种情况下执行完整扫描时,递归结束。
通过实验,我发现通过这种非常简单的方法,可以搜索通过将元素f(i,j,k)
设置为max(f(i-1,j,k), f(i,j-1,k), f(i,j,k-1)) + random(100)
生成的100x200x300元素的数组中间值,并且t = 1仅检查约3%的元素(在范围内找到的每个元素检查25个元素)。
Data 100x200x300 = 6000000 elements, range [83, 48946]
Looking for [24594-1=24593, 24594+1=24595]
Result size = 6850 (5.4 ms)
Full scan = 6850 (131.3 ms)
Search count = 171391 (25.021x, 2.857%)
答案 3 :(得分:0)
由于函数不减少,我认为你可以用二进制搜索做一些事情
在(x, 1, 1)
(列)向量中,您可以进行二进制搜索,以找到符合您要求的范围O(log(n))
。
要查找要查找的列向量,可以对(x, y, 1)
(切片)向量进行二进制搜索,仅检查第一个和最后一个点,以了解该值是否可以落入其中,这将再次采用O(log(n))
。
要知道要查看哪些切片,您可以二元搜索整个多维数据集,检查需要(0, 0), (x, 0), (x, y), (0, y)
的4个点(O(log(n))
)。
总的来说,算法将采用log(z) + a * log(y) + b * log(x)
,其中a
是匹配切片的数量,b
是匹配列的数量。
天真地计算最坏的情况是O(y * z * log(x))
。