题目地址:
https://www.lintcode.com/problem/game-of-life/description
给定一个
0
−
1
0-1
0−1矩阵,按照下面的要求改变该矩阵:
1、若某处为
1
1
1,如果其八个方向的邻居(如果在边界那么邻居会少于八个)有
2
2
2或
3
3
3个
1
1
1,则该处不改变,否则改为
0
0
0;
2、若某处为
0
0
0,并且其八个方向的邻居恰好有
3
3
3个
1
1
1,则该处改为
1
1
1,否则不变。
求改变后的矩阵。
为了保存改变之前每个位置的状态,我们用二进制的两个位来解决这个问题。 0 = 00 0=00 0=00表示原来该处是 0 0 0,将要变为 0 0 0; 1 = 01 1=01 1=01表示原来该处是 1 1 1,将要变为 0 0 0; 2 = 10 2=10 2=10表示原来该处是 0 0 0,将要变为 1 1 1; 3 = 11 3=11 3=11表示原来该处是 1 1 1,将要变为 1 1 1。这样就可以先将每个位置先变为上述二进制表示来做标记,起过渡作用,然后最后再将每个位置置为 0 0 0或者 1 1 1。代码如下:
public class Solution {
/**
* @param board: the given board
* @return: nothing
*/
public void gameOfLife(int[][] board) {
// Write your code here
// 判空
if (board == null || board.length == 0 || board[0].length == 0) {
return;
}
// 先将每个位置变为中间过渡状态
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
int curState = board[i][j], liveNeighbors = computeLiveNeighbors(board, i, j);
// 如果当前状态是1,并且有2或3个值为1的邻居,则说明该处的1要变为1,所以置为(11) = 3;
// 否则该处的1要变为0,置为(01) = 1也就是不变;
// 如果当前状态是0,则当且仅当其有3个值为1的邻居,才会变成1,所以置为(10) = 2
if (curState == 1 && (liveNeighbors == 2 || liveNeighbors == 3)) {
board[i][j] = 3;
} else if (liveNeighbors == 3) {
board[i][j] = 2;
}
}
}
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
board[i][j] = ((board[i][j] & 2) == 2) ? 1 : 0;
}
}
}
// 算一下board[x][y]有多少个值为1的邻居
private int computeLiveNeighbors(int[][] board, int x, int y) {
int count = 0;
int[][] dir = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}};
for (int i = 0; i < dir.length; i++) {
int nextX = x + dir[i][0], nextY = y + dir[i][1];
if (inBound(board, nextX, nextY)) {
// 一个位置的状态是1当且仅当其二进制的最低位等于1
int curState = board[nextX][nextY] & 1;
count += curState;
}
}
return count;
}
private boolean inBound(int[][] board, int x, int y) {
return 0 <= x && x < board.length && 0 <= y && y < board[0].length;
}
}
时间复杂度 O ( m n ) O(mn) O(mn),空间 O ( 1 ) O(1) O(1)。