Leetcode 289.生命游戏
1 题目描述(Leetcode题目链接)
根据百度百科,生命游戏,简称为生命,是英国数学家约翰·何顿·康威在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]
]
进阶:
- 你可以使用原地算法解决本题吗?请注意,面板上所有格子需要同时被更新:你不能先更新某些格子,然后使用它们的更新后的值再更新其他格子。
- 本题中,我们使用二维数组来表示面板。原则上,面板是无限的,但当活细胞侵占了面板边界时会造成问题。你将如何解决这些问题?
2 题解
题目还蛮长的,但是很好理解,通常第一个想到的就是再开辟一个二维数组来记录每个位置发生的变化,很简单,所以直接考虑原地算法,我的思路是使用4个字符来表示四种状态:
- a a a代表原来是死的,将要变成活的,变化为 0 → 1 0\rightarrow1 0→1
- b b b代表原来是活的,将要变成死的,变化为 1 → 0 1\rightarrow0 1→0
- c c c代表原来是死的,依旧是死的,变化为 0 → 0 0\rightarrow0 0→0
- d d d代表原来是活的,依旧是活的,变化为 1 → 1 1\rightarrow1 1→1
通过第一次遍历二维数组,将每个数组元素替换成上述四个字符之一,然后第二次遍历数组的时候再根据字符的定义将其替换为0或1。
class Solution:
def gameOfLife(self, board: List[List[int]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
m = len(board)
n = len(board[0])
direct = [[0,1],[0,-1],[1,0],[-1,0],[1,1],[1,-1],[-1,1],[-1,-1]]
for i in range(m):
for j in range(n):
if board[i][j] == 0:
cnt_1 = 0
for d in direct:
x, y = i+d[0], j+d[1]
if x >= 0 and y >= 0 and x < m and y < n and (board[x][y] in [1,'b','d']):
cnt_1 += 1
board[i][j] = 'a' if cnt_1 == 3 else 'c'
else:
cnt_1 = 0
for d in direct:
x, y = i+d[0], j+d[1]
if x >= 0 and y >= 0 and x < m and y < n and (board[x][y] in [1,'b','d']):
cnt_1 += 1
board[i][j] = 'b' if cnt_1 < 2 or cnt_1 > 3 else 'd'
for i in range(m):
for j in range(n):
if board[i][j] == 'a' or board[i][j] == 'd':
board[i][j] = 1
else:
board[i][j] = 0
有用位运算来记录信息的题解,巧用位运算真的很赞。
class Solution(object):
def gameOfLife(self, board):
def count_cell(x, y):
points = [
(x-1, y-1),
(x-1, y),
(x-1, y+1),
(x, y-1),
(x, y+1),
(x+1, y-1),
(x+1, y),
(x+1, y+1),
]
return sum((board[i][j] & 1) for i, j in points if 0 <= i < max_x and 0 <= j < max_y)
if not board:
return board
max_x, max_y = len(board), len(board[0])
# 计算周围细胞数目,并储存
for i in range(max_x):
for j in range(max_y):
count = count_cell(i, j)
count <<= 1
board[i][j] |= count
for i in range(max_x):
for j in range(max_y):
count = board[i][j] >> 1 # 右移一位,取出周围细胞数目
board[i][j] &= 1 # 重新设置原先细胞状态
if board[i][j] == 1:
if count < 2 or count > 3:
board[i][j] = 0
else:
if count == 3:
board[i][j] = 1
return board