[leetcode/lintcode 题解] 算法面试高频题详解:生命游戏

描述
根据百度百科,生命游戏,简称为生命,是英国数学家约翰·何顿·康威在1970年发明的细胞自动机。
给定一个包含 m × n 个格子的面板,每一个格子都可以看成是一个细胞。每个细胞具有一个初始状态 live(1)即为活细胞, 或 dead(0)即为死细胞。每个细胞与其八个相邻位置(水平,垂直,对角线)的细胞都遵循以下四条生存定律:

  1. 如果活细胞周围八个位置的活细胞数少于两个,则该位置活细胞死亡;
  2. 如果活细胞周围八个位置有两个或三个活细胞,则该位置活细胞仍然存活;
  3. 如果活细胞周围八个位置有超过三个活细胞,则该位置活细胞死亡;
  4. 如果死细胞周围正好有三个活细胞,则该位置死细胞复活;

根据当前状态,写一个函数来计算面板上细胞的下一个(一次更新后的)状态。下一个状态是通过将上述规则同时应用于当前状态下的每个细胞所形成的,其中细胞的出生和死亡是同时发生的。

在线评测地址:领扣题库官网

样例1
输入: 
[
  [0,1,0],
  [0,0,1],
  [1,1,1],
  [0,0,0]
]
输出: 
[
  [0,0,0],
  [1,0,1],
  [0,1,1],
  [0,1,0]
]
  1. 你可以使用原地算法解决本题吗?请注意,面板上所有格子需要同时被更新:你不能先更新某些格子,然后使用它们的更新后的值再更新其他格子。
  2. 本题中,我们使用二维数组来表示面板。原则上,面板是无限的,但当活细胞侵占了面板边界时会造成问题。你将如何解决这些问题?

解题思路
原地完成更新的方法:
我们用32位整数的最后两位二进制来表示boardi的当前状态以及下一状态,0 表示死细胞,1 表示活细胞。由于初始时board由 0 和 1 构成,所以我们设定最低位的二进制表示当前细胞的状态,倒数第二位二进制表示下一状态,不同的表示对应的结果如下:

  • 00 -- 当前为死细胞且下一状态仍为死细胞
  • 01 -- 当前为活细胞且下一状态为死细胞
  • 10 -- 当前为死细胞且下一状态为活细胞
  • 11 -- 当前为活细胞且下一状态仍为活细胞

对于前两种情况我们不需要做改动,因为给出的board内所有元素的倒数第二位均为0,所以需要修改的为后两种情况:
当死细胞周围正好有 3 个活细胞时,则满足第三种状态,所以需要重新赋值:boardi = 2
当活细胞周围正好有 2 个或者 3 个活细胞时,则满足第四种状态,所以需要重新赋值:boardi = 3

源代码

class Solution:
    """
    @param board: the given board
    @return: nothing
    """
    def gameOfLife(self, board):
        # Write your code here
        m = len(board)
        n = len(board[0])
    
        for i in range(m):
            for j in range(n):
                # 计算与board[i][j]相邻的活细胞数量
                lives = self.liveNeighbors(board, m, n, i, j);
                
                # 如果当前位置为活细胞,且相邻活细胞数量为2个或者3个,则下一状态仍为活细胞
                if board[i][j] == 1 and lives >= 2 and lives <= 3:  
                    board[i][j] = 3
                
                # 如果当前位置为死细胞,且相邻活细胞数量为3个,则下一状态为活细胞
                if board[i][j] == 0 and lives == 3:
                    board[i][j] = 2
        
        # 更新细胞状态
        for i in range(m):
            for j in range(n):
                board[i][j] >>= 1
    
    def liveNeighbors(self, board, m, n, i, j):
        lives = 0
        for x in range(max(i - 1, 0), min(i + 1, m - 1) + 1):
            for y in range(max(j - 1, 0), min(j + 1, n - 1) + 1):
                lives += board[x][y] & 1
        lives -= board[i][j] & 1
        return lives

更多题解参考:九章官网solution

上一篇:iOS中 性能优化之浅谈load与initialize 韩俊强的博客


下一篇:[leetcode/lintcode 题解] 算法面试真题详解:最大值在界内的子数组个数