LeetCode-289 生命游戏

LeetCode-289 生命游戏

题目:

According to the Wikipedia’s article: “The Game of Life, also known simply as Life, is a cellular automaton devised by the British mathematician John Horton Conway in 1970.”

Given a board with m by n cells, each cell has an initial state live (1) or dead (0). Each cell interacts with its eight neighbors (horizontal, vertical, diagonal) using the following four rules (taken from the above Wikipedia article):

Any live cell with fewer than two live neighbors dies, as if caused by under-population.
Any live cell with two or three live neighbors lives on to the next generation.
Any live cell with more than three live neighbors dies, as if by over-population…
Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction.
Write a function to compute the next state (after one update) of the board given its current state. The next state is created by applying the above rules simultaneously to every cell in the current state, where births and deaths occur simultaneously.

题目理解:

本题是模拟一个生命游戏(game of life)。给定一个二维矩阵,每个元素代表一个细胞,数值表示细胞状态,1代表活着,0代表死亡。每个细胞的状态都会影响其领域的细胞(本题是8领域)。每个细胞的下一个状态也取决于邻域细胞的当前状态,遵循如下四条规则:
任何一个活细胞,其八邻域内活着的邻居数量少于2个,它下个状态就会死掉;
任何一个活细胞,活着的邻居数量是2或者3个,它下个状态依然活着;
任何一个活细胞,活着的邻居数量超过3个,下个状态死亡;
任何一个死细胞,活着的邻居恰好为3个,那么下个状态就变为活着。
这个题目要求我们实现一个函数,输入当前的细胞生存状态,得到下个时刻的状态。

关于生命游戏和元胞自动机

生命游戏是一个很有趣的数学问题,根据参数可以描述为每个细胞会根据周围的细胞状态决定自己下个时刻的状态。这类问题最初是冯·诺依曼发现晶体或细胞自我复制时提出的元胞自动机概念,生命游戏是元胞自动机的一个模型。生命游戏根据存活或死亡的状态可以呈现为二维的图案,随着不断迭代下去,根据参数不同可能会出现达到稳定状态、震荡状态以及杂乱无序的混沌状态,这一部分也是数学领域的有趣问题之一。mathematica的作者Stephen Wolfram大佬研究过一维情况下的元胞自动机,得到了很有趣的结论。感兴趣的朋友们可以在深入了解一下。

解法

回到这个问题,实际上如果不做任何限制,我们只要新建一个跟输入一样大的二维数组,遍历原数组,对每个细胞遍历其邻域判断下一个状态,然后填到新数组中即可。
但是本题的函数声明为:

void solution::gameOfLife(vector<vector<int>>& board);

“暗示”我们这是一个在原地的修改。但是原地直接从0改到1或者1改到0,那么后面的细胞如果邻域包括被修改的细胞就可能影响当前细胞的下一个状态,因此我们要考虑扩展状态。由于状态间的变化只能有4种情况:
0到1;0到0;1到0;1到1.我们可以将状态扩展为0,1,2,3四个。为了方便状态判断以及后续将状态快速变为0-1的状态,我们可以规定:
0 -> 0 : 0
0 -> 1 : 3
1 -> 0 : 2
1 -> 1 : 1
这样若当前细胞邻域细胞状态值为1或者2,代表这是活着的细胞;
而1,3状态代表下一时刻是存活细胞;0,2代表下一时刻是死亡细胞。
换言之,全部状态判断完毕后,值对2取模就可以得到我们需要的0-1二元状态。
因此,我们采取这样的思路:遍历所有细胞,对每个细胞记录邻域内活细胞的数量,根据细胞当前状态及周围活细胞数量,将当前细胞的状态更改为我们设置的4状态值;然后在遍历一遍所有细胞,对每个状态值取模即可。
C++代码如下:

void gameOfLife(vector<vector<int>>& board)
{
	// 0 -> 0 : 0
	// 0 -> 1 : 3
	// 1 -> 0 : 2
	// 1 -> 1 : 1
	//1 & 2 means this is a live cell in current state
	//0 & 3 means this is a dead cell in current state
	//0 & 2 means this will be dead in next state
	//1 & 3 means this will be live in next state
	int rows = board.size(), cols = board[0].size();
	vector<int> dr = { -1,-1,-1,0,0,1,1,1 }, dc = { -1,0,1,-1,1,-1,0,1 };
	for (int i = 0; i < rows; ++i) {
		for (int j = 0; j < cols; ++j) {
			int cnt = 0;
			for (int k = 0; k < 8; ++k) {
				if (i + dr[k] >= 0 && i + dr[k] < rows && j + dc[k] >= 0 && j + dc[k] < cols && (board[i + dr[k]][j + dc[k]] == 1 || board[i + dr[k]][j + dc[k]] == 2)) ++cnt;
			}
			if (board[i][j] == 1) {
				if (cnt < 2 || cnt>3) board[i][j] = 2;
			}
			else {
				if (cnt == 3) board[i][j] = 3;
			}
		}
	}
	for (int i = 0; i < rows; ++i) {
		for (int j = 0; j < cols; ++j) {
			board[i][j] = board[i][j] % 2;
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值