leetcode 289. Game of Life

来源:互联网 发布:四川长虹人工智能 编辑:程序博客网 时间:2024/06/08 06:32

According to the Wikipedia's article: "The Game of Life, also known simply as Life, is a cellular automaton(细胞自动机) devised by the British mathematician John Horton Conway in 1970."

Given a board with m by n cells, each cell has an initial state live (1) or dead (0). Each cell interacts with its eight neighbors (horizontal, vertical, diagonal) using the following four rules (taken from the above Wikipedia article):

  1. Any live cell with fewer than two live neighbors dies, as if caused by under-population.
  2. Any live cell with two or three live neighbors lives on to the next generation.
  3. Any live cell with more than three live neighbors dies, as if by over-population..
  4. Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction.

Write a function to compute the next state (after one update) of the board given its current state.

Follow up

  1. Could you solve it in-place? Remember that the board needs to be updated at the same time: You cannot update some cells first and then use their updated values to update other cells.
  2. In this question, we represent the board using a 2D array. In principle, the board is infinite, which would cause problems when the active area encroaches the border of the array. How would you address these problems?

这道题难点在于不能使用额外的空间,只能在它给予的 board 上作修改。

为了在原有的数组空间中解决该问题,我们使用 2 bits 来存储 4 个状态:

[2nd bit, 1st bit] = [next state, current state]- 00  dead (next) <- dead (current)     状态0:死->死- 01  dead (next) <- live (current)     状态1:活->死- 10  live (next) <- dead (current)     状态2:死->活- 11  live (next) <- live (current)     状态3:活->活

要得到 board[i][j] 的当前状态,只需要如下操作。奇数 代表当前状态是 活的,偶数 代表当前状态是 死的。

board[i][j] % 2

要得到 board[i][j] 的下一个状态,只需要如下操作。≥2 代表下一状态是 活的,<2 代表下一状态是 死的。

board[i][j] / 2
//活->活=3   活->死=1//死->死=0   死->活=2public void gameOfLife(int[][] board) {if(board.length==0||board[0].length==0){return;}int m=board.length;int n=board[0].length;for(int i=0;i<m;i++){for(int j=0;j<n;j++){int liveNeighbors=getLiveCells(board, m, n, i, j);//Any live cell with fewer than two live neighbors dies.//Any live cell with two or three live neighbors lives.//Any live cell with more than three live neighbors dies.//Any dead cell with exactly three live neighbors becomes a live cell.if(board[i][j]%2==1){  //如果当前cell是活着的if(liveNeighbors<2||liveNeighbors>3){board[i][j]=1;  //活->死}else{board[i][j]=3;  //活->活}}else{  //如果当前cel是死着的if(liveNeighbors==3){board[i][j]=2;  //死->活}else{board[i][j]=0;  //死->死}}}}for(int i=0;i<m;i++){for(int j=0;j<n;j++){board[i][j]=board[i][j]/2;}}return;}public int getLiveCells(int[][] board,int m,int n,int i,int j){int count=0;int[][] directions=new int[][]{{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};for(int c=0;c<8;c++){int x=i+directions[c][0];int y=j+directions[c][1];if(x<0||x>=m||y<0||y>=n){continue;}if(board[x][y]%2==1){count++;}}return count;}

对于follow-up问题中的:In principle, the board is infinite, which would cause problems when the active area encroaches the border of the array. How would you address these problems?

大神表示:Instead of 使用 1,0 二维数组,而是使用 live cell 坐标集合 来表示该 board。

在 set 中存放的是所有活着的细胞的坐标集合。那么如何计算 活着的邻居个数 呢?可以遍历 live cell 集合,然后增加它们邻居的计数器(所以那些没有活着邻居的细胞将不会出现在这个计数器中)。最后,我们通过提取那些拥有正确数量活着邻居的细胞,来放入新的 live cell 集合。

    private Set<Coord> getNewLives(Set<Coord> live) {        Map<Coord,Integer> neighbours = new HashMap<>();        for (Coord cell : live) {            for (int i = cell.i-1; i<cell.i+2; i++) {                for (int j = cell.j-1; j<cell.j+2; j++) {                    if (i==cell.i && j==cell.j) continue;                    Coord c = new Coord(i,j);                    if (neighbours.containsKey(c)) {                        neighbours.put(c, neighbours.get(c) + 1);                    } else {                        neighbours.put(c, 1);                    }                }            }        }        Set<Coord> newLive = new HashSet<>();        for (Map.Entry<Coord,Integer> cell : neighbours.entrySet())  {            if (cell.getValue() == 3 || cell.getValue() == 2 && live.contains(cell.getKey())) {                newLive.add(cell.getKey());            }        }        return newLive;    }

where Coord is:

    private static class Coord {        int i;        int j;        private Coord(int i, int j) {            this.i = i;            this.j = j;        }        public boolean equals(Object o) {            return o instanceof Coord && ((Coord)o).i == i && ((Coord)o).j == j;        }        public int hashCode() {            int hashCode = 1;            hashCode = 31 * hashCode + i;            hashCode = 31 * hashCode + j;            return hashCode;        }    }

and the wrapper:

    public void gameOfLife(int[][] board) {        Set<Coord> live = new HashSet<>();        int m = board.length;        int n = board[0].length;        for (int i = 0; i<m; i++) {            for (int j = 0; j<n; j++) {                if (board[i][j] == 1) {                    live.add(new Coord(i,j));                }            }        };        live = getNewLives(live);        for (int i = 0; i<m; i++) {            for (int j = 0; j<n; j++) {                board[i][j] = live.contains(new Coord(i,j))?1:0;            }        };            }


原创粉丝点击