【问题标题】:find neighbours in 2d array by position of elements通过元素的位置在二维数组中查找邻居
【发布时间】:2020-03-10 08:53:52
【问题描述】:

我需要通过元素的位置在二维数组中找到邻居

可用数据:

网格大小。例如 - 3*3 将返回 3,4*4 将返回 4

网格中填充单元格的数量。例如 - 4

获取填充单元格的 x 坐标 - 例如 0 或 1 或 2 等

获取填充单元格的 y 坐标 - 例如 0 或 1 或 2 等

例如

int[][] room = {
            {0, 0, X},
            {0, X, 0},
            {X, 0, 0}
    };

这里,网格大小 = 3

网格中填充单元格的数量 = 3(因为有三个“X”,所以它在其他单元格上的值无关紧要)

获取填充单元格的 x 坐标 - 第一个元素为 0,第二个元素为 1,第三个元素为 2

获取填充单元格的 y 坐标 - 第一个元素为 2,第二个元素为 1,第三个元素为 0

所以,坐标变成(0,2),(1,1),(2,0)

我需要计算至少有一个相邻“X”的“X”的数量。如果“X”在基本方向上彼此相邻,而不是对角线,则将它们视为邻居。 所以上面的情况会返回 0。

int[][] room = {
            {X, X, 0},
            {0, 0, 0},
            {0, 0, 0}
    };

这应该返回 2。

我使用的语言是 Java。

我尝试迭代填充元素的数量并使用如下所示的邻居逻辑,但在某些情况下它会中断 你上方的邻居 = (x, y-1),

你下面的邻居 = (x, y+1),

你左边的邻居 = (x-1, y),

你右边的邻居 = (x+1, y)

for (int x = 0; x < nums; x++) {
        int xcord = xmap.get(x); //return x cord
        int ycord = ymap.get(x); //return y cord
        int xcordLeft = x - 1 >= 0 ? xmap.get(x - 1) : 0;
        int ycordLeft = x - 1 >= 0 ? ymap.get(x - 1) : 0;

        int xcordRight = x + 1 < size ? xmap.getOrDefault(x + 1, 0) : 0;
        int ycordRight = x + 1 < size ? ymap.getOrDefault(x + 1, 0) : 0;

        int xcordTop = xcord - 1 >= 0 ? xmap.get(xcord - 1) : 0;
        int ycordTop = ymap.get(ycord);

        int ycordBottom = ymap.get(ycord);*/
        //left
        if (xcord >= 0 && x - 1 >= 0 && xcord == xcordLeft && ycord - 1 == ycordLeft) {
            neighbours++;
        }
        //right
        if (xcord >= 0 && x + 1 < size && xcord == xcordRight && ycord + 1 == ycordRight) {
            neighbours++;
        }
        //top
        if (xcord >= 0 && xcord - 1 >= 0 && xcord - 1 == xcordTop && ycord == ycordTop) {
            neighbours++;
        }

        //bottom
    }

【问题讨论】:

    标签: java arrays algorithm data-structures


    【解决方案1】:

    您正在从指定 X 所在位置的坐标列表中工作。

    两个单元格p(xp, yp) 是 q(xq, y q) 在曼哈顿距离为 1 时相邻:

        | xp - xq | + | yp - yq | = 1

    不要试图找到顶部、底部、左侧和右侧邻居的坐标并在列表中查找它们,而是遍历列表并计算邻居数:

    for (int i = 0; i < nums; i++) {
        int x = xmap.get(i);
        int y = ymap.get(i);
        int neighbors = 0;
    
        for (int j = 0; j < nums; j++) {
            int xx = xmap.get(j);
            int yy = ymap.get(j);
    
            if ((abs(x - xx) + abs(y - yy) == 1) {
                neighbors++;
            }
        }
    
        if (neighbors) // do stuff
    }
    

    一个单元到它自己的曼哈顿距离是 0,所以它不算是邻居。该代码对于大而密集的网格不是很有效,但如果 X 很少,嵌套的 lops 应该没问题。

    【讨论】:

      【解决方案2】:

      简单明了。
      通过检查所有四个相邻坐标来计数邻居,并有一些条件来检查相邻坐标是否在边界内:

      bool inBounds(int x, int y){
          return 0 <= x and x < size and 0 <= y and y < size;
      }
      
      int countNeighbours(int x, int y) {
          int count = 0;
          for(int i=-1; i<=1; i+=2){
              if(inBounds(x+i, y))
                  if(data[x+i][y] == X){
                      count++;
                  }
              }
              if(inBounds(x, y+i))
                  if(data[x][y+i] == X){
                      count++;
                  }
              }
          }
          return count;
      }
      
      int countGroupedEntries(){
          int count = 0;
          for(int x=0; x<size; x++){
              for(int y=0; y<size; y++){
                  if(data[x][y] == X){
                      if(countNeighbours(x,y) != 0){
                          count++;
                      }
                  }
              }
          }
          return count;
      }
      

      我的意思是,这里的某些算法可能更聪明,但是如果您没有一些效率瓶颈,请使算法尽可能简单,使其可读(并不是说这个算法特别糟糕,在 Θ( size²) 很好,唯一需要考虑的是线性因素)。
      执行inBounds 检查而不是确保您在特殊情况下保持在界限内,可以防止countNeighbours 方法过度拥挤。

      【讨论】:

        【解决方案3】:

        我假设您将所有 x 的坐标按顺序存储在两张地图中(一张用于 x,一张用于 y)。 比如

            {X , X , 0 , X},
            {X , 0 , X , X}
            {0 , 0 , X , X}
            {X , X,  0 , 0}
        

        所以你的地图会有这样的条目

            xmap = {
                    0 : 0,
                    1 : 1,
                    2 : 3,
                    3 : 0,
                    4 : 2,
                    5 : 3,
                    6 : 2,
                    7 : 3,
                    8 : 0,
                    9 : 1
                }
            ymap = {
                    0 : 0,
                    1 : 0,
                    2 : 0,
                    3 : 1,
                    4 : 1,
                    5 : 1,
                    6 : 2,
                    7 : 2,
                    8 : 3,
                    9 : 3,
                }
        

        我觉得左右可以这样编辑

              //left
                if (xcord >= 0 && x - 1 >= 0 && xcord - 1 == xcordLeft && ycord == ycordLeft) {
                    neighbours++; //comparing (x - 1 , y) && (x , y)
                }
              //right
                if (xcord >= 0 && x + 1 < size && xcord + 1 == xcordRight && ycord == ycordRight) {
                    neighbours++; // comparing(x , y) && (x + 1 , y)
                }
        

        实际上 xcordTop 应该是 ycordTop 但我们假设它相当于找到顶部元素

        the mistake you are doing is that how can you be sure that
        int xcordTop = xcord - 1 >= 0 ? xmap.get(xcord - 1) : 0; will give you coordinate of just upper element, because key of
        the map is not x coordinates it is just numbering of X'S
        

        所以对于给定矩阵中的第 7 个 X(其索引是 0 中的 6 编号),让我们取它的 x 和 y 坐标

        xcord = 2 
        ycord = 2
        now let's us take xmap.get(2)
        what do we get xcordTop = 0
        

        即使我们从 ycordTop 逻辑出发,它也会再次给我们错误的坐标,因为地图键值只是序列的值 总X

        so let's take ymap.get(ycord) 
        ycord = 2
        so ycordTop = ymap.get(2) 
        we get ycordTop = 0 so which is 0th row
        

        所以一个简单的解决方案就是遍历二维数组 并检查你提到的所有邻居,这将是

        for(int y = 0; y < array.length; ++y){
            for(int x = 0; x < array[y].length; ++x){
                if(array[x][y] == 'X'){
                    if(x - 1 >= 0 && array[x - 1][y] == 'X'){
                        ++neighbors;
                    }
                    else if(x + 1 < array[y].length && array[x + 1][y] == 'X'){
                        ++neighbors;
                    }
                    else if(y - 1 >= 0  && array[x][y - 1] == 'X'){
                        ++neighbors;
                    }
                    else if(y + 1 < array.length && array[x][y + 1] == 'X'){
                        ++neighbors;
                    }
                }
            }
        }
        

        【讨论】:

          【解决方案4】:

          如果你想计算邻里关系的数量,你可以:

          private int countNeighborRelations(int[][] array, int yourX) {
              int neighborRelationCount = 0;
              for (int y = 0; y < array.length; y++) {
                  for (int x = 0; x < array[y].length - 1; x++) {
                      if (array[y][x] == yourX && array[y][x + 1] == yourX) {
                          neighborRelationCount += 2;
                      }
                  }
              }
              for (int y = 0; y < array.length - 1; y++) {
                  for (int x = 0; x < array[y].length; x++) {
                      if (array[y][x] == yourX && array[y + 1][x] == yourX) {
                          neighborRelationCount += 2;
                      }
                  }
              }
              return neighborRelationCount;
          }
          

          如果您想计算您的 X 中有多少有 neigbourHoodRelations(换句话说,所有 X 至少有一个邻居),您可以使用以下代码:

          private int countNeighbors(int[][] array, int yourX) {
              int[][] neighborRelationCount = new int[array.length][array[0].length];
              for (int y = 0; y < array.length; y++) {
                  for (int x = 0; x < array[y].length - 1; x++) {
                      if (array[y][x] == yourX && array[y][x + 1] == yourX) {
                          neighborRelationCount[y][x]++;
                          neighborRelationCount[y][x + 1]++;
                      }
                  }
              }
              for (int y = 0; y < array.length - 1; y++) {
                  for (int x = 0; x < array[y].length; x++) {
                      if (array[y][x] == yourX && array[y + 1][x] == yourX) {
                          neighborRelationCount[y][x]++;
                          neighborRelationCount[y + 1][x]++;
                      }
                  }
              }
              int neighbourCount=0;
              for (int y = 0; y < neighborRelationCount.length; y++) {
                  for (int x = 0; x < neighborRelationCount[y].length; x++) {
                      if (0<neighborRelationCount[y][x]) {
                          neighbourCount++;
                      }
                  }
              }
              return neighbourCount;
          }
          

          如果你确实使用其他数据格式,当然有更简单的解决方案,但使用原始 int[][] 我认为这是最简单的方法。

          这是我测试功能的方法:

              @Test
              public void testRelations() {
                  // TODO Auto-generated method stub
                  int[][] room0_0 = { { 1, 0, 1 }, { 0, 1, 0 }, { 1, 0, 1 } };
                  int[][] room2_2 = { { 1, 1, 0 }, { 0, 0, 0 }, { 0, 0, 0 } };
                  int[][] room4_3 = { { 1, 1, 0 }, { 0, 1, 0 }, { 0, 0, 0 } };
                  int[][] room4_4 = { { 1, 1, 0 }, { 0, 0, 0 }, { 0, 1, 1 } };
                  int[][] room8_5 = { { 1, 1, 0 }, { 0, 1, 0 }, { 0, 1, 1 } };
                  int[][] room24_9 = { { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 } };
                  assertTrue(countNeighborRelations(room0_0, 1)==0);
                  assertTrue(countNeighborRelations(room2_2, 1)==2);
                  assertTrue(countNeighborRelations(room4_3, 1)==4);
                  assertTrue(countNeighborRelations(room4_4, 1)==4);
                  assertTrue(countNeighborRelations(room8_5, 1)==8);
                  assertTrue(countNeighborRelations(room24_9, 1)==24);
                  assertTrue(countNeighbors(room0_0, 1)==0);
                  assertTrue(countNeighbors(room2_2, 1)==2);
                  assertTrue(countNeighbors(room4_3, 1)==3);
                  assertTrue(countNeighbors(room4_4, 1)==4);
                  assertTrue(countNeighbors(room8_5, 1)==5);
                  assertTrue(countNeighbors(room24_9, 1)==9);
              }
          

          EDIT 为请求的全部功能添加了完整的实现

          以下代码的复杂度为 O(gridSize^2)

          private int neigbours(Collection<CoordinatedObject> cos,int gridSize) {
              boolean[][] array=new boolean[gridSize][gridSize];
              for(CoordinatedObject co:cos) {
                  array[co.getX()][co.getY()]&=true;
              }
              boolean[][] neighborRelations = new boolean[array.length][array[0].length];
              for (int y = 0; y < array.length; y++) {
                  for (int x = 0; x < array[y].length - 1; x++) {
                      if (array[y][x] && array[y][x + 1]) {
                          neighborRelations[y][x]&=true;
                          neighborRelations[y][x + 1]&=true;
                      }
                  }
              }
              for (int y = 0; y < array.length - 1; y++) {
                  for (int x = 0; x < array[y].length; x++) {
                      if (array[y][x] && array[y + 1][x]) {
                          neighborRelations[y][x]&=true;
                          neighborRelations[y + 1][x]&=true;
                      }
                  }
              }
              int neighbourCount=0;
              for (int y = 0; y < neighborRelations.length; y++) {
                  for (int x = 0; x < neighborRelations[y].length; x++) {
                      if (neighborRelations[y][x]) {
                          neighbourCount++;
                      }
                  }
              }
              return neighbourCount;
          }
          

          【讨论】:

          • 谢谢@samuel。但我认为它不起作用。我从传递第一个数组和 x-cord 的循环中调用了 countNeighbors 方法,它返回 6,0,0(三次迭代),而理想情况下应该返回 0。
          • 请问你是怎么测试的?我还添加了我的测试进行比较;)
          • 我明白了。您将元素值作为“yourX”传递。不幸的是,原始问题中没有数组,只有坐标。但我想我可以使用这些坐标填充数组,然后传递该值。
          • 好的,抱歉,我好像误解了你的问题,但根据你的猜测,它肯定会起作用。
          • @SCoder 如果为您的代码添加了完整的解决方案。如果您不需要性能,我认为答案link 更好(更具可读性)如果您需要非常高的性能,您也可以结合这两种解决方案。由于另一个具有 O(n^2) 的 Compexitivity 并且我的一个 O(greedSize^2) 另一个对于大型松散网格可能更快。 (如果 n
          猜你喜欢
          • 2010-10-13
          • 2017-10-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-09-22
          • 2022-11-19
          • 1970-01-01
          相关资源
          最近更新 更多