算法的重要性,我就不多說了吧,想去大廠,就必須要經(jīng)過基礎知識和業(yè)務邏輯面試+算法面試。所以,為了提高大家的算法能力,這個公眾號后續(xù)每天帶大家做一道算法題,題目就從LeetCode上面選 !今天和大家聊的問題叫做 生命游戲,我們先來看題面:https://leetcode-cn.com/problems/game-of-life/根據(jù) 百度百科 ,生命游戲,簡稱為生命,是英國數(shù)學家約翰·何頓·康威在 1970 年發(fā)明的細胞自動機。給定一個包含 m × n 個格子的面板,每一個格子都可以看成是一個細胞。每個細胞都具有一個初始狀態(tài):1 即為活細胞(live),或 0 即為死細胞(dead)。每個細胞與其八個相鄰位置(水平,垂直,對角線)的細胞都遵循以下四條生存定律:如果活細胞周圍八個位置的活細胞數(shù)少于兩個,則該位置活細胞死亡;
如果活細胞周圍八個位置有兩個或三個活細胞,則該位置活細胞仍然存活;
如果活細胞周圍八個位置有超過三個活細胞,則該位置活細胞死亡;
如果死細胞周圍正好有三個活細胞,則該位置死細胞復活;
下一個狀態(tài)是通過將上述規(guī)則同時應用于當前狀態(tài)下的每個細胞所形成的,其中細胞的出生和死亡是同時發(fā)生的。給你 m x n 網(wǎng)格面板 board 的當前狀態(tài),返回下一個狀態(tài)。示例
解題
https://leetcode-cn.com/problems/game-of-life/solution/sheng-ming-you-xi-by-leetcode-solution/使用額外的狀態(tài)
題目中每個細胞只有兩種狀態(tài) live(1) 或 dead(0),但我們可以拓展一些復合狀態(tài)使其包含之前的狀態(tài)。舉個例子,如果細胞之前的狀態(tài)是 0,但是在更新之后變成了 1,我們就可以給它定義一個復合狀態(tài) 2。這樣我們看到 2,既能知道目前這個細胞是活的,還能知道它之前是死的。
根據(jù)數(shù)組的細胞狀態(tài)計算新一輪的細胞狀態(tài),這里會用到能同時代表過去狀態(tài)和現(xiàn)在狀態(tài)的復合狀態(tài)。規(guī)則 1:如果活細胞周圍八個位置的活細胞數(shù)少于兩個,則該位置活細胞死亡。這時候,將細胞值改為 -1,代表這個細胞過去是活的現(xiàn)在死了;規(guī)則 2:如果活細胞周圍八個位置有兩個或三個活細胞,則該位置活細胞仍然存活。這時候不改變細胞的值,仍為 1;規(guī)則 3:如果活細胞周圍八個位置有超過三個活細胞,則該位置活細胞死亡。這時候,將細胞的值改為 -1,代表這個細胞過去是活的現(xiàn)在死了??梢钥吹?,因為規(guī)則 1 和規(guī)則 3 下細胞的起始終止狀態(tài)是一致的,因此它們的復合狀態(tài)也一致;規(guī)則 4:如果死細胞周圍正好有三個活細胞,則該位置死細胞復活。這時候,將細胞的值改為 2,代表這個細胞過去是死的現(xiàn)在活了。根據(jù)新的規(guī)則更新數(shù)組;現(xiàn)在復合狀態(tài)隱含了過去細胞的狀態(tài),所以我們可以在不復制數(shù)組的情況下完成原地更新;對于最終的輸出,需要將 board 轉(zhuǎn)成 0,1 的形式。因此這時候需要再遍歷一次數(shù)組,將復合狀態(tài)為 2 的細胞的值改為 1,復合狀態(tài)為 -1 的細胞的值改為 0。class Solution {
public void gameOfLife(int[][] board) {
int[] neighbors = {0, 1, -1};
int rows = board.length;
int cols = board[0].length;
// 遍歷面板每一個格子里的細胞
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
// 對于每一個細胞統(tǒng)計其八個相鄰位置里的活細胞數(shù)量
int liveNeighbors = 0;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (!(neighbors[i] == 0 && neighbors[j] == 0)) {
// 相鄰位置的坐標
int r = (row + neighbors[i]);
int c = (col + neighbors[j]);
// 查看相鄰的細胞是否是活細胞
if ((r < rows && r >= 0) && (c < cols && c >= 0) && (Math.abs(board[r][c]) == 1)) {
liveNeighbors += 1;
}
}
}
}
// 規(guī)則 1 或規(guī)則 3
if ((board[row][col] == 1) && (liveNeighbors < 2 || liveNeighbors > 3)) {
// -1 代表這個細胞過去是活的現(xiàn)在死了
board[row][col] = -1;
}
// 規(guī)則 4
if (board[row][col] == 0 && liveNeighbors == 3) {
// 2 代表這個細胞過去是死的現(xiàn)在活了
board[row][col] = 2;
}
}
}
// 遍歷 board 得到一次更新后的狀態(tài)
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
if (board[row][col] > 0) {
board[row][col] = 1;
} else {
board[row][col] = 0;
}
}
}
}
}
好了,今天的文章就到這里,如果覺得有所收獲,請順手點個在看或者轉(zhuǎn)發(fā)吧,你們的支持是我最大的動力 。