我有一个三维数组,其中的值是单调递增或递减的。如何找到所有满足 |f(X,Y,Z) – v1| < t 的 (x,y)。
我有一个三维数组,其中的值是单调递增或递减的。如何找到所有满足 |f(X,Y,Z) – v1| < t 的 (x,y)。
有Omega(n^2)个点,它们的坐标总和为n-1。事先不知道这些点的值如何相互比较,因此在最坏情况下,必须检查所有这些点。通过在每个常数z切片中运行2D算法,可以提供与常数因子相匹配的上限。
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;
}
f(i,j,k)
为max(f(i-1,j,k), f(i,j-1,k), f(i,j,k-1)) + random(100)
并检查范围内符合条件的元素,仅需检查约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%)
v1
),执行以下步骤:
v2
等),保留函数评估的缓存,并为每个值重新执行算法。对于100^3,密集数组足够。由于函数是非递减的,我认为你可以用二分搜索来做一些事情。
在一个 (x, 1, 1)
(列)向量中,您可以进行二分搜索以找到与您的要求匹配的范围,这将需要 O(log(n))
的时间。
要查找哪些列向量,请对 (x, y, 1)
(切片)向量进行二分搜索,仅检查第一个和最后一个点以确定该值是否可以落在它们之间,这将再次需要 O(log(n))
的时间。
要知道要查找哪些切片,请对整个立方体进行二分搜索,检查4个点 ((0, 0), (x, 0), (x, y), (0, y)
),这将需要 O(log(n))
的时间。
因此,总体而言,该算法将需要 log(z) + a * log(y) + b * log(x)
的时间,其中 a
是匹配切片的数量,b
是匹配列的数量。
最坏情况下的朴素计算是 O(y * z * log(x))
。