【问题标题】:How to handle List of list Integer and find neighbours?如何处理列表整数列表并查找邻居?
【发布时间】:2023-03-27 10:57:01
【问题描述】:

我目前正在尝试解决输入应如下所示的问题

int hours(int rows, int columns, List<List<Integer> > grid)

其中列表网格是 0 和 1 的矩阵(0 表示不完整,1 表示完整)如下:

0 1 1 0 1 
0 1 0 1 0 
0 0 0 0 1 
0 1 0 0 0 

每个值代表网络中的一台机器互相发送文件,因此如果值为“1”,则该节点能够将文件发送给所有邻居(对角线不计算在内)仅上/下/右/左)。问题是一旦 0 变为 1(受相邻单元的影响),它就无法在 1 小时之前将文件发送给任何其他邻居。

问题的目标是返回所有节点接收文件需要多少小时? (换句话说,所有的矩阵都变成了 1。考虑运行时间复杂度

为了直观的解释:(在第一个小时之后,这应该是矩阵的状态,被认为是一次迭代):

 1 1 1 1 1
 1 1 1 1 1
 0 1 0 1 1
 1 1 1 0 1

所以,我采用了一种方法,在矩阵中循环查看提供的网格并将值附加到临时数组中(因为我不知道如何更新或附加主列表中的列表值)。然后,一旦行索引达到最大值,我将 1 小时添加到 int 变量并将值添加到主网格。

我知道下面的代码还没有工作/完成,可能有语法错误,但你明白了这个想法和方法。

我的问题是,有没有比我的更简单有效的方法?我还找到了一个解决方案here,但如果我的想法值得的话,这只适用于二维数组。但是,这 4 个嵌套循环不会弄乱代码的复杂性吗?

    List<List<Integer>> grid2 = grid1;
    boolean received= false;
    int hours=0;
    int rows_Temp = 0 ;
    int columsTemp = 0 ;
    int[][] grid2 = null ;
    while(rows_Temp<rows&&!received)
    {
        if(rows_Temp==rows-1)
        { 
            rows_Temp=0;
        }
        if(rows_Temp==0) 
        {
            //create an array with the grid dimention
            grid2= new int[rows][columns];
        }
        //manage top left corner
        if(rows_Temp==0 && columsTemp == 0 ) 
        {
            //find right & down
            int center= grid.get(rows_Temp).get(columsTemp);
            int right = grid.get(rows_Temp).get(columsTemp+1);
            int down  = grid.get(rows_Temp+1).get(columsTemp);


            if(center==1)
            {
                if(right==0)
                {
                    grid2[rows_Temp][columsTemp+1] = 1;
                }
                if(down==0)
                {
                    grid2[rows_Temp+1][columsTemp]=1;
                }
            }
        }
        //manage top right corner
        else if(rows_Temp==0 && columsTemp == columns-1)
        {
            //find left and down
            int center= grid.get(rows_Temp).get(columsTemp);
            int left = grid.get(rows_Temp).get(columsTemp-1);
            int down  = grid.get(rows_Temp+1).get(columsTemp);

            if(center==1)
            {
                if(left==0)
                {
                    grid2[rows_Temp][columsTemp-1] = 1;
                }
                if(down==0)
                {
                    grid2[rows_Temp+1][columsTemp]=1;
                }
            }
        }
        //mange down left corner of the array
        else if(rows_Temp==rows-1 && columsTemp == 0)
        {
            //find up and right
            int center= grid.get(rows_Temp).get(columsTemp);
            int right = grid.get(rows_Temp).get(columsTemp+1);
            int up  = grid.get(rows_Temp-1).get(columsTemp);

            if(center==1)
            {
                if(right==0)
                {
                    grid2[rows_Temp][columsTemp+1] = 1;
                }
                if(up==0)
                {
                    grid2[rows_Temp-1][columsTemp]=1;
                }
            }
        }
        //manage down right corner
        else if(rows_Temp==rows-1 && columsTemp == columns-1)
        {
            //find left and up
            int center= grid.get(rows_Temp).get(columsTemp);
            int left = grid.get(rows_Temp).get(columsTemp-1);
            int up  = grid.get(rows_Temp-1).get(columsTemp);

            if(center==1)
            {
                if(left==0)
                {
                    grid2[rows_Temp][columsTemp-1] = 1;
                }
                if(up==0)
                {
                    grid2[rows_Temp-1][columsTemp]=1;
                }
            }
        }
        //manage left sides but not corners
        else if(rows_Temp!=0&& rows_Temp!=rows-1&& columsTemp==0)
        {
            int center= grid.get(rows_Temp).get(columsTemp);
            int right = grid.get(rows_Temp).get(columsTemp+1);
            int up  = grid.get(rows_Temp-1).get(columsTemp);
            int down  = grid.get(rows_Temp+1).get(columsTemp);

            if(center==1)
            {
                if(right==0)
                {
                    grid2[rows_Temp][columsTemp+1] = 1;
                }
                if(up==0)
                {
                    grid2[rows_Temp-1][columsTemp]=1;
                }
                if(down==0)
                {
                    grid2[rows_Temp+1][columsTemp]=1;
                }
            }  
        }    

        if(columsTemp==columns-1)
        {
            columsTemp=0;
            rows_Temp++;
            System.out.println();
        }
        else
        {
            columsTemp++;
        }


    }
    System.out.println("------------");
    return 0 ;
}

【问题讨论】:

  • 根据你的例子,我认为对角线邻居不算数。
  • 是的,只有上/下/右/左
  • 您应该从最初的 1 开始进行广度优先搜索。遍历所有单元格所需的层数是填充矩阵的小时数。
  • 好的,谢谢,我会搜索算法,但在那之前会检查周围的上/下/左右并能够将零更改为一吗??
  • 不确定我是否告诉过你所陈述的问题......但我在问题中写的第二次迭代发生在第一个小时结束时......并且该典型测试用例的解决方案是2 小时,因为第三次迭代会将它们全部变成一个

标签: java algorithm data-structures runtime time-complexity


【解决方案1】:

如果允许您更新grid,请使用grid.get(y).get(x) 检查网格并使用grid.get(y).set(x, value) 更新网格。如果不允许更新网格,请先将值复制到 int[][] 二维数组中,然后在下面的解决方案中使用它。

扫描网格中的0 值,并将坐标添加到Queue&lt;Point&gt;,例如一个ArrayDeque&lt;Point&gt;,其中Point 是一个具有两个int 字段的对象,例如java.awt.Point 类。

我们这样做是为了确保良好的性能,运行时间复杂度为O(nm),其中nm 是网格的宽度和高度。

i = 1 开始一个循环。在循环中,迭代队列。如果该点的相邻值等于i,则将该点值设置为i + 1,否则将该点添加到第二个队列。最后,将第一个队列替换为第二个队列,将i加1再做一遍,直到队列为空。

结果是这样的 2D 矩阵的级数:

0 1 1 0 1   →   2 1 1 2 1   →   2 1 1 2 1   →   2 1 1 2 1
0 1 0 0 0   →   2 1 2 0 2   →   2 1 2 3 2   →   2 1 2 3 2
0 0 0 0 1   →   0 2 0 2 1   →   3 2 3 2 1   →   3 2 3 2 1
0 0 0 1 0   →   0 0 2 1 2   →   0 3 2 1 2   →   4 3 2 1 2

矩阵中的最大值是 4,所以答案是 3 小时,比最大值小 1。


更新

这里是代码,它将输入复制到一个二维数组,并将值降低 1,因为这样更有意义。

static int hours(int rows, int columns, List<List<Integer>> grid) {
    // Build hourGrid, where value is the number of hours until the
    // node can send, with MAX_VALUE meaning the node cannot send.
    // Also build queue of nodes that cannot send.
    int[][] hourGrid = new int[rows][columns];
    Queue<Point> pending = new ArrayDeque<>();
    for (int y = 0; y < rows; y++) {
        for (int x = 0; x < columns; x++) {
            if (grid.get(y).get(x) == 0) {
                hourGrid[y][x] = Integer.MAX_VALUE;
                pending.add(new Point(x, y));
            }
        }
    }

    // Keep iterating the queue until all pending nodes can send.
    // Each iteration adds 1 hour to the total time.
    int hours = 0;
    for (; ! pending.isEmpty(); hours++) {
        // Check all pending nodes if they can receive data
        Queue<Point> notYet = new ArrayDeque<>();
        for (Point p : pending) {
            if ((p.x > 0           && hourGrid[p.y][p.x - 1] <= hours)
             || (p.x < columns - 1 && hourGrid[p.y][p.x + 1] <= hours)
             || (p.y > 0           && hourGrid[p.y - 1][p.x] <= hours)
             || (p.y < rows - 1    && hourGrid[p.y + 1][p.x] <= hours)) {
                // Node can receive from a neighbor, so will be able to send in 1 hour
                hourGrid[p.y][p.x] = hours + 1;
            } else {
                // Not receiving yet, so add to queue for next round
                notYet.add(p);
            }
        }
        pending = notYet;
    }
    return hours;
}

为了测试,构建一个List&lt;List&lt;Integer&gt;&gt;,并发送单独的rowscolumns值,很麻烦,所以这里有一个辅助方法:

static int hours(int[][] grid) {
    final int rows = grid.length;
    final int columns = grid[0].length;
    List<List<Integer>> gridList = new ArrayList<>(rows);
    for (int[] row : grid) {
        List<Integer> rowList = new ArrayList<>(columns);
        for (int value : row)
            rowList.add(value); // autoboxes
        gridList.add(rowList);
    }
    return hours(rows, columns, gridList);
}

测试

System.out.println(hours(new int[][] { // data from question
    { 0, 1, 1, 0, 1 },
    { 0, 1, 0, 1, 0 },
    { 0, 0, 0, 0, 1 },
    { 0, 1, 0, 0, 0 },
}));
System.out.println(hours(new int[][] { // data from answer
    { 0, 1, 1, 0, 1 },
    { 0, 1, 0, 0, 0 },
    { 0, 0, 0, 0, 1 },
    { 0, 0, 0, 1, 0 },
}));

输出

2
3

【讨论】:

  • 我非常感谢我正在寻找的这个信息 grid.get(y).set(x, value)。我的解决方案中唯一的问题是,在整个迭代结束之前,您将无法编辑主网格。换句话说,当具有 1 的节点更改邻居时,它只会在下一次迭代中影响它们,尽管它们对于当前的节点仍然是相同的(至少我对此的理解)
  • 我不完全理解你的答案理论,所以如果你能分享一些代码会很好,但唯一的问题是解决方案是 2 小时而不是 3 小时
  • @RaymondHaniArtin 我的例子和你的例子不一样,所以my例子的解法是3小时。
  • 哦,好的,非常感谢,然后我将尝试编写该代码,但这不会使复杂度 o(n^2) ? 或 o(mn) 不同??
  • @RaymondHaniArtin 如果n是节点数,即n = width * height,那么这个答案是O(n)answer by WJSO( n²)(最坏情况,即矩阵为 1*n 且开头或结尾只有一个 1)。
【解决方案2】:

这似乎奏效了。


      List<List<Integer>> grid = 
            new ArrayList<>(List.of(
      new ArrayList<>(List.of(0, 1, 1, 0, 1)),
      new ArrayList<>(List.of( 0, 1, 0, 1, 0)),
      new ArrayList<>(List.of( 0, 0, 0, 0, 1)),
      new ArrayList<>(List.of( 0, 1, 0, 0, 0))));

      int total =0; 
      while (hours(4,4,grid) > 0) {
         total++;
      }

      System.out.println(total + " hours");

   }

   public static void display(List<List<?>> grid) {
      for (List<?> row : grid) {
         System.out.println(row);
      }
      System.out.println();
   }
   public static int hours(int rows, int cols, List<List<Integer>> grid) {
      int count = 0;

      // count the remaining 0's and change
      // the new guys to 1.
      for (int r = 0; r < rows; r++) {
         for (int c = 0; c < cols; c++) {
            if (grid.get(r).get(c) == 0) {
               count++;
            }
            if (grid.get(r).get(c) == -2) {
               grid.get(r).set(c, 1);
            }
         }
      }
      if (count == 0) {
         return 0;
      }
      for (int r = 0; r < rows; r++) {
         for (int c = 0; c < cols; c++) {

            if (grid.get(r).get(c) == 1 && grid.get(r).get(c) != -2) {
               if (r + 1 < rows) {
                  if (grid.get(r + 1).get(c) == 0) {
                     grid.get(r + 1).set(c, -2);
                  }
               }
               if (r - 1 >= 0) {
                  if (grid.get(r - 1).get(c) == 0) {
                     grid.get(r - 1).set(c, -2);
                  }
               }
               if (c + 1 < cols) {
                  if (grid.get(r).get(c + 1) == 0) {
                     grid.get(r).set(c + 1, -2);
                  }
               }
               if (c - 1 >= 0) {
                  if (grid.get(r).get(c - 1) == 0) {
                     grid.get(r).set(c - 1, -2);
                  }
               }
            }
         }
      }

      return count;
   }
}


【讨论】:

  • 你能解释一下为什么吗?仅代码答案并没有真正的帮助。这是我们都学到的解释。
  • 我目前无法访问 PC 进行测试,但如果输出为 2 小时,那么我想这是最佳解决方案
  • 然而,另一个问题是计算所用算法的复杂度......所以如果你想参加这个挑战,请与我们分享?
  • 一开始你不需要等待一个小时......第一次迭代的结束发生在第一个小时的结束......并且您不允许更改该方法的输入参数是 int rows int columns 和 list>
  • 是的,我的意思是......在编写代码时应该考虑优化......并且绝对动态列表的大小可能会改变
猜你喜欢
  • 2022-08-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-29
  • 1970-01-01
相关资源
最近更新 更多