Java 求矩阵上波的中心的最佳算法是什么?

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 |

考虑到我有这样一个矩阵(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 | 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-#-
      ----------------
      #-#-#-#-#-#-#-#-
      ----------------