leetcode:289. 生命游戏

题目来源

题目描述

在这里插入图片描述
在这里插入图片描述

题意分析

本题的两个关键点

(1)其生存规律总结如下

在这里插入图片描述
(2)前一秒变过的细胞状态不会影响下一个细胞状态。问题是新的状态是基于初始状态来变化的,但是如果修改了原数组,会影响后继状态的判断。怎么办呢?

  • 复制一个初始状态,然后修改board
  • 使用位运算

使用位运算

一个 int 有 32 bit,输入数据只用了一个 bit,所以我们可以利用其他空闲的bit位进行“原地修改”。

  • 1代表细胞活的, 0 代表细胞死的,那么这个位置就四种状态,用【下一个状态,当前状态】表示,最后需要用右移操作更新结果
    • 状态 0: 00 ,死的,下一轮还是死的
    • 状态 1: 01,活的,下一轮死了
    • 状态 2: 10,死的,下一轮活了
    • 状态 3: 11,活的,下一轮继续活着
  • 进一步:下一轮活的可能有两种,也就是要把单元格变为1
    • 这个活细胞周围八个位置有两个或三个活细胞,下一轮继续活,属于11
    • 这个细胞本来死的,周围有三个活着的,下一轮复活了,属于 10

那遍历下每个格子看他周围细胞有多少个活细胞就行了,然后更改为状态,那么对于第一种可能,把 board[i][j]设置为 33,对于第二种可能状态设置为 2,设置个高位flag,遍历后面的格子,拿到与他相邻的格子中有多少个 alive 的,和 1与一下即可,最后我们把 board[i][j]右移 1位,更新结果

class Solution {
    std::vector<std::vector<int>> dirs {
            {-1, -1}, {-1, 0}, {-1, 1}, {0, -1},
            {0, 1}, {1, -1}, {1, 0}, {1, 1}
    };
    
    // 当前位置范围内有多少活细胞
    int liveCount( vector<vector<int>> &board, int i, int j){
        int N = board.size(), M = board[0].size();
        int ans = 0;
        for(auto d : dirs){
            int pi = i + d[0], pj = j + d[1];
            if(pi < 0 || pj < 0 || pi == N || pj == M){
                continue;
            }
            // 如果这个位置为 0,代表当前轮是死的,不需要算进去
            // 如果这个位置为 1,代表当前轮是活得,需要算进去
            // 如果这个位置为 2,代表当前轮是死的(状态10,下一轮是活的),不需要算进去
            // 如果这个位置为 3,代表是当前轮是活的(状态11,下一轮也是活的),需要算进去
            ans += (board[pi][pj] & 1);
        }
        return ans;
    }
   
public:
    void gameOfLife(vector<vector<int>>& board) {
        if(board.empty() || board[0].empty()){
            return;
        }
        int N = board.size(), M = board[0].size();
        for (int i = 0; i < N; ++i) {
            for (int j = 0; j < M; ++j) {
                // 拿到当前位置周围活细胞数量
                int cnt = liveCount(board, i, j);
                // 1. 活细胞周围八个位置有两个或三个活细胞,下一轮继续活 
                if (board[i][j] == 1 && (cnt == 2 || cnt == 3)) board[i][j] = 3;
                // 2. 死细胞周围有三个活细胞,下一轮复活了
                if (board[i][j] == 0 && cnt == 3) board[i][j] = 2;
            }
        }

        // 更新结果
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                board[i][j] >>= 1;
            }
        }
    }
};

使用辅助数组

class Solution {
    std::vector<std::vector<int>> dirs {
            {-1, -1}, {-1, 0}, {-1, 1}, {0, -1},
            {0, 1}, {1, -1}, {1, 0}, {1, 1}
    };
    
    // 当前位置范围内有多少活细胞
    int liveCount( vector<vector<int>> &original, int i, int j){
        int N = original.size(), M = original[0].size();
        int ans = 0;
        for(auto d : dirs){
            int pi = i + d[0], pj = j + d[1];
            if(pi < 0 || pj < 0 || pi == N || pj == M){
                continue;
            }
            ans += original[pi][pj];
        }
        return ans;
    }
   
public:
    void gameOfLife(vector<vector<int>>& board) {
        if(board.empty() || board[0].empty()){
            return;
        }
        vector<vector<int>> original = board;
        int N = original.size(), M = original[0].size();
        for (int i = 0; i < N; ++i) {
            for (int j = 0; j < M; ++j) {
                int cnt = liveCount(original, i, j);
                if((original[i][j] == 0 && cnt == 3)
                || (original[i][j] == 1 && (cnt == 2 || cnt == 3))){
                    board[i][j] = 1;
                }else{
                    board[i][j] = 0;
                }
            }
        }
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值