最近家里降温
冻得手敲字都抖
这难道是老天都想让我好好休息?
题目描述:
根据百度百科,生命游戏,简称为生命,是英国数学家约翰·何顿·康威在1970年发明的细胞自动机。
给定一个包含 m × n 个格子的面板,每一个格子都可以看成是一个细胞。每个细胞具有一个初始状态 live(1)即为活细胞, 或 dead(0)即为死细胞。每个细胞与其八个相邻位置(水平,垂直,对角线)的细胞都遵循以下四条生存定律:
如果活细胞周围八个位置的活细胞数少于两个,则该位置活细胞死亡;
如果活细胞周围八个位置有两个或三个活细胞,则该位置活细胞仍然存活;
如果活细胞周围八个位置有超过三个活细胞,则该位置活细胞死亡;
如果死细胞周围正好有三个活细胞,则该位置死细胞复活;
根据当前状态,写一个函数来计算面板上细胞的下一个(一次更新后的)状态。下一个状态是通过将上述规则同时应用于当前状态下的每个细胞所形成的,其中细胞的出生和死亡是同时发生的。
示例:
输入:
[
[0,1,0],
[0,0,1],
[1,1,1],
[0,0,0]
]
输出:
[
[0,0,0],
[1,0,1],
[0,1,1],
[0,1,0]
]
思路解析:
看到网上有位大佬对此类题目的解答非常精髓,凡是碰到in-place更新数组的题目,基本上都是两次遍历,逐步更新的。第一次遍历,就是要将更新后的值用其他数字来代替,避免更新后该数字对下一个数字的更新产生影响。第二次遍历,则是将所有更新后的数字对照相应关系恢复为原始数组中出现的数值。对于本题而言呢,思路如下:
第一次遍历时也是分两种情况:
若活细胞变成了死细胞,由1->-1, 若活细胞还是存活,由1->3;
若死细胞变成了活细胞,由0->2, 若死细胞还是死亡,由0->-2;
第二次遍历则是将2, 3->1, -1, -2->0
代码如下:
class Solution(object):
def gameOfLife(self, board):
"""
两次遍历,
第一次遍历时也是分两种情况:
若活细胞变成了死细胞,由1->-1, 若活细胞还是存活,由1->3;
若死细胞变成了活细胞,由0->2, 若死细胞还是死亡,由0->-2;
第二次遍历则是将2, 3->1, -1, -2->0
这样可以避免每次迭代更新时上一次的细胞状态对下一次更新细胞的影响
:type board: List[List[int]]
:rtype: None Do not return anything, modify board in-place instead.
"""
def count_num(start_row, start_col, end_row, end_col):
lives = 0
for row in range(start_row, end_row+1):
for col in range(start_col, end_col+1):
if board[row][col] in [-1, 1, 3]:
lives += 1
return lives
row_len, col_len = len(board), len(board[0])
for row in range(row_len):
start_row = max(0, row - 1)
end_row = min(row_len-1, row+1)
for col in range(col_len):
start_col, end_col = max(0, col - 1), min(col_len-1, col+1)
lives = count_num(start_row, start_col, end_row, end_col)
if board[row][col] == 1:
lives -= 1
if lives < 2 or lives > 3:
board[row][col] = -1
else:
board[row][col] = 3
else:
if lives == 3:
board[row][col] = 2
else:
board[row][col] = -2
# 第二次遍历,恢复更改的值
for row in range(row_len):
for col in range(col_len):
if board[row][col] >= 2:
board[row][col] = 1
else:
board[row][col] = 0
if __name__ == "__main__":
board = [[0, 1, 0], [0, 0, 1], [1, 1, 1], [0, 0, 0]]
Solution().gameOfLife(board)
执行效率能达到90%