每天一道LeetCode-----生命游戏
来源:互联网 发布:淘宝sy仓什么意思 编辑:程序博客网 时间:2024/06/05 19:02
Game of Life
原题链接 Game of Life
生命游戏,计算下一个状态。游戏规则如下
- 对于一个live的细胞,如果它周围live的细胞数量少于两个,那么它将dead
- 对于一个live的细胞,如果它周围live的细胞数量是两个或三个,那么它继续live
- 对于一个live的细胞,如果它周围live的细胞数量超过三个,那么它将dead
- 对于一个dead的细胞,如果它周围live的细胞数量恰好是三个,那么它将live
给定某一时刻各个细胞的状态,用二维数组表示,1表示live,0表示dead。需要返回下一个状态,要求只能在原数组中更改,即空间复杂度在O(n)
不过有一点需要主要,每个细胞周围有8个细胞,判断这个细胞下一个状态依据的是它周围那么细胞的状态。比说如当前状态为A,下一个状态为B。那么对于某个处于状态A的细胞而言,要判断它下一个状态,依据的是它周围8个细胞的A状态,而不是B状态。
这就要求不能一边遍历一边修改,只能先遍历一遍,记录好哪些细胞需要改变状态。然后在第二遍遍历的时候更新状态。
记录的方式比较多,比如
增加几个细胞的状态,如2代表现在是live并且下一个状态也是live;3代表现在是live但是下一个状态是dead;4代表现在是dead但是下一个状态是live
这样,所有细胞当前的状态和下一个状态就都知道了,在第二次遍历时,只需要根据2,3,4做适当的修改即可
代码如下
class Solution {public: void gameOfLife(vector<vector<int>>& board) { //2 : current is live and next is live //3 : current is live but next is dead //4 : current is dead but next is live if(board.empty() || board[0].empty()) return; int m = board.size(); int n = board[0].size(); for(int i = 0; i < m; ++i) { for(int j = 0; j < n; ++j) { int liveCount = 0; /* 判断周围live的细胞数量 */ for(int p = std::max(0, i - 1); p < std::min(m, i + 2); ++p) { for(int q = std::max(0, j - 1); q < std::min(n, j + 2); ++q) { if(p == i && q == j) continue; if(isLive(board, p, q)) ++liveCount; } } /* 根据周围细胞数量改变状态 */ if(liveCount < 2 && isLive(board, i, j)) board[i][j] = 3; else if(liveCount > 3 && isLive(board, i, j)) board[i][j] = 3; else if(liveCount == 3 && !isLive(board, i, j)) board[i][j] = 4; } } /* 第二次遍历时改变状态 */ for(int i = 0; i < m; ++i) { for(int j = 0; j < n; ++j) { if(board[i][j] == 3) board[i][j] = 0; else if(board[i][j] == 4) board[i][j] = 1; } } }private: /* 一个细胞处于live的条件是当前状态是live而不是下一个状态是live */ bool isLive(vector<vector<int>>& board, int i, int j) { return board[i][j] == 1 || board[i][j] == 2 || board[i][j] == 3; }};
除了上面提到的增加细胞状态的方法外,还有一种方法可以记录细胞的当前状态和下一个状态。
因为最开始,细胞只有0和1两种状态,只需要一个字节即可记录,也就是说int类型的其它位置实际上是用不上的。所以,可以将int类型其它字节用上,来记录细胞的下一个状态,不过只需要一个字节即可。
0和1的二进制码分别是0000和0001,表示细胞处于dead状态和live状态。如果试图将下一个状态也记录在这里面,就像
- 0000表示当前状态是dead并且下一个状态是dead,值为0
- 0010表示当前状态是dead并且下一个状态是live,值为2
- 0001表示当前状态是live并且下一个状态是dead,值为1
- 0011表示当前状态是live并且下一个状态是live,值为3
这样,在第二遍遍历时只需要将每个细胞的值右移一位,就从当前状态变为下一个状态了。
代码如下
class Solution {public: void gameOfLife(vector<vector<int>>& board) { if(board.empty() || board[0].empty()) return; int m = board.size(); int n = board[0].size(); for(int i = 0; i < m; ++i) { for(int j = 0; j < n; ++j) { int liveCount = 0; for(int p = std::max(0, i - 1); p < std::min(m, i + 2); ++p) { for(int q = std::max(0, j - 1); q < std::min(n, j + 2); ++q) { /* 这里没有排除p == i && q == j */ liveCount += (board[p][q] & 1); } } /* 对于live的细胞,它下一个状态仍然是live的条件是算上它本身,周围live的细胞数量是3或4个 */ /* 对于dead的细胞,它下一个状态是live的条件是算上它本身,周围live的细胞数量是3个 */ /* 不能直接liveCount == 4因为对于dead的细胞是错误的 */ if(liveCount == 3 || liveCount - board[i][j] == 3) board[i][j] |= 2; } } for(int i = 0; i < m; ++i) { for(int j = 0; j < n; ++j) { board[i][j] >>= 1; } } }};
本题和每天一道LeetCode—–给定一个矩阵,如果某个元素是0,就将所在行所在列上所有元素否置0类似,都是在第一遍遍历时在原二维数组上做记录,在第二遍遍历时集中更改。从而保证空间复杂度为O(1),但是如何记录,需要仔细考虑
- 每天一道LeetCode-----生命游戏
- 每天一道LeetCode-----字符串乘法
- 每天一道LeetCode-----括号匹配
- 每天一道LeetCode-----数独盘求解
- 每天一算法(生命游戏)
- 每天一道leetcode题目_(1)
- 【每天一道leetcode】1:N-Queens
- 每天一道LeetCode-----回文链表
- 每天一道LeetCode-----重新实现next_permutation
- 每天一道LeetCode-----n皇后问题
- 每天一道LeetCode-----化简路径
- 每天一道LeetCode-----逆序链表
- 289. Game of Life-LeetCode(生命游戏)
- 每天一道编程题(一)----24点游戏
- 生命游戏
- 生命游戏
- 生命游戏
- 生命游戏
- 四位计算机领域先驱者
- 自学软件测试怎么学?
- 由memcpy越界引起的崩溃
- 小白每天学习两个函数D9-(stock)
- 用strtok分割字符串
- 每天一道LeetCode-----生命游戏
- CodeForces
- 3XML 语法规则
- Android Stuido app工程手机图标变成咖啡杯图标
- 最大堆
- maven中依赖管理的详细解说
- Android-studio的Error总结
- nginx模块开发初体验
- linux下安装vpn服务器和vpn客户端