Java 求矩阵上波的中心的最佳算法是什么?
考虑到我有这样一个矩阵(mXn):Java 求矩阵上波的中心的最佳算法是什么?,java,algorithm,Java,Algorithm,考虑到我有这样一个矩阵(mXn): 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 0 | 1 | 1 | 2 | 1 | 1 | 0 | 0 | 0 0 | 1 | 4 | 9 | 4 | 1 | 0 | 0 | 0 1 | 2 | 9 | # | 9 | 2 | 1 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0
0 | 1 | 1 | 2 | 1 | 1 | 0 | 0 | 0
0 | 1 | 4 | 9 | 4 | 1 | 0 | 0 | 0
1 | 2 | 9 | # | 9 | 2 | 1 | 0 | 0
0 | 1 | 4 | 9 | 4 | 1 | 0 | 0 | 0
0 | 1 | 1 | 2 | 1 | 1 | 0 | 0 | 0
0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0
其中有一个随机设置的点。附近的值会以波浪的形式受到影响。离该点越近,值就越接近10
哪种算法在查找#
(假设它将在更大范围内使用)时效果良好
编辑:我更感兴趣的是如何找到第一个非零数字,而不是查找#
本身,这是目的,但不是真正的问题。
想象一下,一个巨大的矩阵充满了零,而
隐藏在某个地方。算法的详尽部分是找到第一个非零。首先将整个矩阵拆分为7x7
小矩阵,因为矩阵之间的重叠最小化
将矩阵拆分为小矩阵后,遍历或随机选取每个小矩阵的一些点,以检查是否存在非零值
如果从小矩阵中找到任何非零值,请从该非零值中查找。从0,0遍历矩阵,直到找到非零值 一旦你找到了一个非零值,看看顶部、右侧、底部、左侧的邻居,找到最大的一个(如果有多个,就从中选择一个)
然后在你刚刚挑选的最大的一个上再做同样的事情,看看它的4个邻居,找到最大的一个,直到你点击
#
如果周围的图案总是相同的,那么根据相邻元素的值和我们遇到的第一个非零数字,我们总是可以在O(1)时间内预测#
点的正确位置
例如,如果第一个非零数字是1,右元素是1,向下是1,右下对角线是4,那么
#
位于(i+2,j+2),其中(i,j)是当前元素的位置。假设模式始终相同,您希望从[2][2]开始,在每个方向每五个单元格检查一次
直到找到非零的东西。所以您将检查[2][2]、[2][7]、[2][12]、…、[7][2]、[7][7]、[7][12]、…、[12][2]、…
等等
一旦您找到了其中一个非零值的单元格,您就可以检查其相邻单元格及其相邻单元格的相邻单元格,以找到#
字符
这是
O(n^2)
,这是您所能做的最好的,因为您无法避免检查O(n^2)
单元格。因为没有写入任务,我会使用多线程先查找非零数,然后使用单个线程查找。如果矩阵足够大,可以抵消线程处理的低性能,那么这将比单线程处理效果更好
另一种可能的方法是遍历单元格,直到找到第一个非零数。由于非零数保证与波的中心位于同一列中,因此我们可以简单地迭代该列,直到找到
aba
模式(9#9
在示例中)的点,其中b
值将是波的中心
假设:
- 全波存在于矩阵中,因此存在波的最远范围,从而可以找到第一个非零数
- 中心值是唯一的,因为它不等于同一列中的其他值,否则算法将发现中心周围的一个值为中心
然后检查具有r+/-1和c+/-1的邻居,u将找到#。只有在信号对称且不包含旋转时,才能找到第一个非零值。考虑下面的例子从Internet(0=蓝色,max =红色),注意第一个非零值是在右上角的某处:
(来源:) 你可能想看看。通用算法是为连续函数定义的(您的是离散的),但您仍然可以使用它 它基本上是在矩阵的某个地方初始化的,在那个点上寻找梯度并朝那个方向移动,然后重复,直到收敛。您可以通过随机采样对其进行初始化(选择一个随机单元,直到得到一个非零值,您可以预期这比平均遍历并找到一个非零值要快,这自然取决于您的矩阵和信号大小) 一些属性:
- 通常比穷举搜索(迭代整个矩阵)更快
- 搜索空间越大(矩阵),与穷举搜索相比,搜索速度越快
- 即使信号不对称且居中(第一个非零与最大值对齐),您仍然可以处理更复杂的信号李>
- 同样的方法也可以用于一维信号或缩放到n维(仔细想想,这有点酷,也很有用:)
- 它可以永远振荡而不收敛到某个值,特别是在离散函数上,您需要在代码中处理这种情况
- 您不一定能找到全局最大值(可能会陷入局部最大值,有一些方法可以克服这一点)
- 您需要对函数进行插值(不是全部,只是几个单元格,这不是一件困难的事情,我不会使用线性插值),或者对算法进行一些修改(计算
First non zero element-->| 1 | 1 | 2 | 0 | 1 | 4 | 9 | 1 | 2 | 9 | # |
// iterate through cells for (int y = 0; y < matrix.length; y++) { for (int x = 0; x < matrix[0].length; x++) { if (matrix[y][x] > 0) { // first non-zero value, in this case at point 3,3 int cellCurr = 0; int cellOnePrev = 0; int cellTwoPrev = 0; for (; y < matrix.length; y++) { // iterate down rest of column cellCurr = matrix[y][x]; if (cellCurr == cellTwoPrev) { // aba pattern found, center is b System.out.println("found " + cellOnePrev + " at " + x + "," + (y - 1)); return; } // update necessary values cellTwoPrev = cellOnePrev; cellOnePrev = cellCurr; } } } }
found 10 at 3,6
a = max(matrix) [r,c] = find(matrix == a)
import java.awt.Point; public class WaveMatrixTest { public static void main(String[] args) { //basicTest(); speedTest(); } private static void basicTest() { int size = 30; int maxValue = 10; int array[][] = new int[size][size]; placeValue(array, maxValue, 15, 15); System.out.println(toString2D(array)); } private static void speedTest() { int maxValue = 10; int runs = 10; for (int size=2000; size<=8000; size*=2) { for (int run=0; run<runs; run++) { int x = size/2+size/4; int y = size/2+size/4; runTestSimpleA(size, maxValue, x, y); runTestSimpleB(size, maxValue, x, y); runTestSkipping(size, maxValue, x, y); } } } private static void runTestSimpleA(int size, int maxValue, int x, int y) { int array[][] = new int[size][size]; placeValue(array, maxValue, x, y); long before = System.nanoTime(); Point p = findNonZeroSimpleA(array, maxValue); long after = System.nanoTime(); System.out.printf("SimpleA, size %5d max at %5d,%5d took %.3f ms, result %s\n", size, x, y, (after-before)/1e6, p); } private static void runTestSimpleB(int size, int maxValue, int x, int y) { int array[][] = new int[size][size]; placeValue(array, maxValue, x, y); long before = System.nanoTime(); Point p = findNonZeroSimpleB(array, maxValue); long after = System.nanoTime(); System.out.printf("SimpleB, size %5d max at %5d,%5d took %.3f ms, result %s\n", size, x, y, (after-before)/1e6, p); } private static void runTestSkipping(int size, int maxValue, int x, int y) { int array[][] = new int[size][size]; placeValue(array, maxValue, x, y); long before = System.nanoTime(); Point p = findNonZeroSkipping(array, maxValue); long after = System.nanoTime(); System.out.printf("Skipping, size %5d max at %5d,%5d took %.3f ms, result %s\n", size, x, y, (after-before)/1e6, p); } private static void placeValue(int array[][], int maxValue, int x, int y) { int sizeX = array.length; int sizeY = array[0].length; int n = maxValue; for (int dx=-n; dx<=n; dx++) { for (int dy=-n; dy<=n; dy++) { int cx = x+dx; int cy = y+dy; if (cx >= 0 && cx < sizeX && cy >= 0 && cy < sizeY) { int v = maxValue - Math.max(Math.abs(dx), Math.abs(dy)); array[cx][cy] = v; } } } } private static Point findNonZeroSimpleA(int array[][], int maxValue) { int sizeX = array.length; int sizeY = array[0].length; for (int x=0; x<sizeX; x++) { for (int y=0; y<sizeY; y++) { if (array[x][y] != 0) { return new Point(x,y); } } } return null; } private static Point findNonZeroSimpleB(int array[][], int maxValue) { int sizeX = array.length; int sizeY = array[0].length; for (int y=0; y<sizeY; y++) { for (int x=0; x<sizeX; x++) { if (array[x][y] != 0) { return new Point(x,y); } } } return null; } private static Point findNonZeroSkipping(int array[][], int maxValue) { int size = maxValue * 2 - 1; int sizeX = array.length; int sizeY = array[0].length; for (int x=0; x<sizeX; x+=size) { for (int y=0; y<sizeY; y+=size) { if (array[x][y] != 0) { return new Point(x,y); } } } return null; } private static String toString2D(int array[][]) { StringBuilder sb = new StringBuilder(); int sizeX = array.length; int sizeY = array[0].length; for (int x=0; x<sizeX; x++) { for (int y=0; y<sizeY; y++) { sb.append(String.format("%3d", array[x][y])); } sb.append("\n"); } return sb.toString(); } }
#-------#------- ---------------- ---------------- ---------------- ---------------- ---------------- ---------------- ---------------- #-------#------- ---------------- ---------------- ---------------- ---------------- ---------------- ---------------- ----------------
o---#---o---#--- ---------------- ---------------- ---------------- #---#---#---#--- ---------------- ---------------- ---------------- o---#---o---#--- ---------------- ---------------- ---------------- #---#---#---#--- ---------------- ---------------- ----------------
o-#-o-#-o-#-o-#- ---------------- #-#-#-#-#-#-#-#- ---------------- o-#-o-#-o-#-o-#- ---------------- #-#-#-#-#-#-#-#- ---------------- o-#-o-#-o-#-o-#- ---------------- #-#-#-#-#-#-#-#- ---------------- o-#-o-#-o-#-o-#- ---------------- #-#-#-#-#-#-#-#- ----------------