编程难题:如何计算存活细菌的数量?

时间:2019-04-21 15:31:40

标签: java algorithm matrix data-structures grid

最近,我遇到了一个有趣的编程难题,该难题中提到了一些很好的曲折。在令我惊讶的问题之下,我只是很想知道在下面的情况下,java中是否有任何相关的解决方案是否可行。

问题陈述: 有一个尺寸为m * n的网格,最初,在该网格的左下角单元格(m-1,0)中存在细菌,而所有其他单元格都为空。每秒之后,网格中的每种细菌会自我分裂,并使相邻(水平,垂直和对角线)细胞中的细菌数增加1并死亡。

在n-1秒后,右下角的细胞(m-1,n-1)中存在多少细菌? 我参考了 https://www.codechef.com/problems/BGH17 但未能提交解决方案 下面是更多问题现场的图片

enter image description here

3 个答案:

答案 0 :(得分:0)

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.Stack;    

public class BacteriaProblem {
      public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("Number of Rows: ");
        int m = sc.nextInt();
        System.out.println("Number of Columns: ");
        int n = sc.nextInt();
        int[][] input = new int[m][n];
        input[m - 1][0] = 1;
        Stack<String> stack = new Stack<>();
        stack.push(m - 1 + "~" + 0);
        reproduce(stack, input, n - 1);

        System.out.println("Value at Bottom Right corner after n-1 secs: " + input[m - 1][n - 1]);
      }

      private static void reproduce(Stack<String> stack, int[][] input, int times) {
        //exit condition
        if (times < 1) {
          return;
        }

        //bacteria after splitting
        List<String> children = new ArrayList<>();

        //reproduce all existing bacteria
        while (!stack.isEmpty()) {
          String[] coordinates = stack.pop().split("~");
          int x = Integer.parseInt(coordinates[0]);
          int y = Integer.parseInt(coordinates[1]);


          for (int i = -1; i <= 1; i++) {
            for (int j = -1; j <= 1; j++) {
              if (i == 0 && j == 0) continue;
              split(input, x + i, y + j, children);
            }
          }
          input[x][y]--;
        }

        //add all children to stack
        for (String coord : children) {
          stack.push(coord);
        }

        //reduce times by 1
        reproduce(stack, input, times - 1);

      }

      private static void split(int[][] input, int x, int y, List<String> children) {
        int m = input.length;
        int n = input[0].length;

        if (x >= 0 && x < m && y >= 0 && y < n) {
          input[x][y]++;
          children.add(x + "~" + y);
        }
      }
    }

答案 1 :(得分:0)

好吧,我在Online Hackerrank测试中被问到这个问题,当时无法解决。 后来我确实尝试对其进行编码,这是C ++中的解决方案,

long countBacteriasAtBottomRight(int m, int n){
long grid[m][n];

// Set all to 0, and only bottom left to 1
for (int i=0; i<m; i++){
    for (int j=0; j<n; j++){
        grid[i][j] = 0;
    }
}

grid[m-1][0] = 1;

// Start the cycle, do it for (n-1) times
int time = n-1;
vector<long> toBeUpdated;

while (time--){
    cout << "\n\nTime: " << time;

    for (int i=0; i<m; i++){
        for (int j=0; j<n; j++){

            while (grid[i][j] > 0){
                grid[i][j]--;

                // upper left
                if (i > 0 && j > 0){
                    toBeUpdated.push_back(i-1);
                    toBeUpdated.push_back(j-1);
                }

                // upper
                if (i > 0){
                    toBeUpdated.push_back(i-1);
                    toBeUpdated.push_back(j);
                }

                // upper right
                if (i > 0 && j < n-1){
                    toBeUpdated.push_back(i-1);
                    toBeUpdated.push_back(j+1);
                }

                // left
                if (j > 0){
                    toBeUpdated.push_back(i);
                    toBeUpdated.push_back(j-1);
                }

                // bottom left
                if (i < m-1 && j > 0){
                    toBeUpdated.push_back(i+1);
                    toBeUpdated.push_back(j-1);
                }

                // bottom
                if (i < m-1){
                    toBeUpdated.push_back(i+1);
                    toBeUpdated.push_back(j);
                }

                // bottom right
                if (i < m-1 && j < n-1){
                    toBeUpdated.push_back(i+1);
                    toBeUpdated.push_back(j+1);
                }

                // right
                if (j < n-1){
                    toBeUpdated.push_back(i);
                    toBeUpdated.push_back(j+1);
                }
            };
        }
    }

    // Update all other cells
    for (int k=0; k<toBeUpdated.size(); k+=2){          
        grid[toBeUpdated[k]][toBeUpdated[k+1]]++;
    }

    for (int i=0; i<m; i++){
        cout << endl;
        for (int j=0; j<n; j++)
            cout << grid[i][j] << " ";
    }

    // Clear the temp vector
    toBeUpdated.clear();
};

return grid[m-1][n-1];
}

答案 2 :(得分:0)

起始情况仅在最左边的列0中有一个值。我们需要在时间n-1之后知道最右边的列n-1中的情况。这意味着我们只需要查看每列一次:在时间x的列x。在时间x之后,列x发生了什么不再重要。因此,我们从左到右,将上一列中的单元格加起来:

                                                1
                                          1     8
                                    1     7    35
                              1     6    27   104
                        1     5    20    70   230
                  1     4    14    44   133   392
            1     3     9    25    69   189   518
      1     2     5    12    30    76   196   512
1     1     2     4     9    21    51   127   323   ...

您还将注意到,最后一个单元格的结果仅受前一列中的两个单元格的影响,而在此之前的一个中则受三个单元格的影响,因此计算出例如在n = 9的情况下,您只需要计算该三角形中的值:

                        1
                  1     4    14
            1     3     9    25    69
      1     2     5    12    30    76   196
1     1     2     4     9    21    51   127   323

无论网格有多高,我们只需要向上n / 2(向上舍入)行。因此,我们必须计算的总和为n 2 / 4,如果m

还请注意,我们不必一次存储所有这些值,因为我们从左到右逐列进行。因此,我们只需要一个大小为n / 2的一维数组,并且其中的当前值将像这样进行转换(例如,在上面的示例中从第4列变为第5列):

[4, 5, 3, 1]     (0)  ->  0 + 5 - 0 = 5
[9, 5, 3, 1]     (5)  ->  9 + 3 - 5 = 7
[9,12, 3, 1]     (7)  ->  12 + 1 - 7 = 6
[9,12, 9, 1]     (6)  ->  9 + 0 - 6 = 3
[9,12, 9, 4]     (3)  ->  4 + 0 - 3 = 1
[9,12, 9, 4, 1]  (1)  (additional value is always 1)

我们在其中从左到右迭代值,在当前元素的左右添加值,减去一个初始化为0的临时变量,将结果存储在一个临时变量中,然后将其添加到当前元素。


因此,理论上的时间复杂度为O(n 2 )或O(n.m),空间复杂度为O(n)或O(m),以较小者为准。实际上,步数为n 2 / 4,所需空间为n / 2。


我不会讲Java,但这是一个简单的JavaScript代码段,可以轻松翻译:

function bacteria(m, n) {
    var sum = [1];
    for (var col = 1; col < n; col++) {
        var temp = 0;
        var height = Math.min(col + 1, n - col, m);
        if (height > sum.length) sum.push(0);
        for (var row = 0; row < height; row++) {
            var left = row > 0 ? sum[row - 1] : 0;
            var right = row < sum.length - 1 ? sum[row + 1] : 0;
            temp = left + right - temp;
            sum[row] += temp;
        }
    }
    return sum[0];
}
document.write(bacteria(9, 9));