LeetCode 289. Game of Life

准备dropbox的时候又仔细看了看这道题。本题的难点一是in place,二是如果board很大或者无限大怎么办。

 

Naive

class Solution {
public:
    int dirs[8][2]={{-1,0},{1,0},{0,-1},{0,1},{-1,-1},{-1,1},{1,-1},{1,1}};
    
    void gameOfLife(vector<vector<int>>& board) {
        int m=board.size(), n=board[0].size();
        vector<vector<int>> copy(board);
        for (int i=0;i<m;++i){
            for (int j=0;j<n;++j){
                // update board[i][j]
                int count=0;
                for (auto dir:dirs){
                    int ii=i+dir[0], jj=j+dir[1];
                    if (ii<0 || ii>=m || jj<0 || jj>=n) continue;
                    if (copy[ii][jj]==1) ++count;
                }
                if (copy[i][j]==1){
                    if (count<2 || count>3) board[i][j]=0;
                    if (count==2 || count==3) board[i][j]=1; 
                }else{
                    if (count==3) board[i][j]=1;
                    else board[i][j]=0;
                }
            }
        }
    }
};

 

In Place

由于状态用一位表示即可,因此利用两位(two bits)就可以同时记录之前的状态和新状态,进而不用新建一个board。

低位是原来的状态,高位是新状态。

class Solution {
public:
    int dirs[8][2]={{-1,0},{1,0},{0,-1},{0,1},{-1,-1},{-1,1},{1,-1},{1,1}};
    
    void gameOfLife(vector<vector<int>>& board) {
        int m=board.size(), n=board[0].size();
        for (int i=0;i<m;++i){
            for (int j=0;j<n;++j){
                // update higher bit of board[i][j]
                int count=0;
                for (auto dir:dirs){
                    int ii=i+dir[0], jj=j+dir[1];
                    if (ii<0 || ii>=m || jj<0 || jj>=n) continue;
                    if (board[ii][jj]&1==1) ++count;
                }
                if (board[i][j]&1==1){
                    if (count<2 || count>3) board[i][j]=1; // 01
                    if (count==2 || count==3) board[i][j]=3; // 11 
                }else{
                    if (count==3) board[i][j]=2; // 10
                    else board[i][j]=0; // 00
                }
            }
        }
        for (int i=0;i<m;++i){
            for (int j=0;j<n;++j){
                board[i][j] >>= 1;
            }
        }
    }
};

 

Large & Sparse

如果board非常大,那么保存全部的格子十分浪费空间。我们可以只保存live的格子,然后更新neighbor。然后根据规则,得到一轮后新的所有live。下面代码核心部分是 gameOfLifeSparse,剩下的包裹函数用来通过test case的。

这种方法的缺陷是,如果board无限大,我们无法得到所有live格子,内存可能也不够放下。

class Solution {
public:
    struct pair_hash{
        template <class T1, class T2>
        std::size_t operator()(std::pair<T1, T2> const &pair) const {
            std::size_t h1 = std::hash<T1>()(pair.first);
            std::size_t h2 = std::hash<T2>()(pair.second);
            return h1 ^ h2;
        }
    };
    
    int dirs[8][2]={{-1,0},{1,0},{0,-1},{0,1},{-1,-1},{-1,1},{1,-1},{1,1}};
    
    void gameOfLife(vector<vector<int>>& board) {
        int m=board.size(), n=board[0].size();
        unordered_set<pair<int,int>,pair_hash> live;
        for (int i=0;i<m;++i){
            for (int j=0;j<n;++j){
                if (board[i][j]==1) live.insert({i,j});
            }
        }
        
        live = gameOfLifeSparse(live);
        
        for (int i=0;i<m;++i){
            for (int j=0;j<n;++j){
                if (live.count({i,j})) board[i][j] = 1;
                else board[i][j] = 0;
            }
        }
    }
    
    unordered_set<pair<int,int>,pair_hash> gameOfLifeSparse(unordered_set<pair<int,int>,pair_hash> &live){
        unordered_map<pair<int,int>,int,pair_hash> count;
        for (pair<int,int> x:live){
            int i=x.first, j=x.second;
            for (auto dir:dirs){
                int ii=i+dir[0], jj=j+dir[1];
                ++count[{ii,jj}];
            }
        }
        unordered_set<pair<int,int>,pair_hash> new_live;
        for (auto x:count){
            if (x.second==3 || x.second==2 && live.count(x.first))
                new_live.insert(x.first);
        }
        return new_live;
    }
};

 

Infinite

假定board信息都保存在文件里,每次处理三行的中间一行。处理完后删除第一行,从文件新读入一行。

https://leetcode.com/problems/game-of-life/discuss/73217/Infinite-board-solution/201780

class Solution {
public:  
    int dirs[8][2]={{-1,0},{1,0},{0,-1},{0,1},{-1,-1},{-1,1},{1,-1},{1,1}};
    
    void gameOfLifeInfinite(filename) {
        ifstream in(filename);
        string line;

        // deal with the first row and write back
        
        vector<string> threeLineBoard(3);
        for (int i=0;i<3;++i){
            getline(in,line);
            threeLineBoard.push_back(line);
        }

        while (true){
            for (int i=0;i<threeLineBoard[1].size();++i){
                // update the middle row in place
                // write the updated middle row back to file, we can calculate the position
                // e.g. write to ith line, then go to i*(lengh of row) using file.seekg()
            }

            threeLineBoard.erase(threeLineBoard.begin());
            getline(in,line);
            if (line=="") break;
            threeLineBoard.push_back(line);
        }

        // deal with the last row and write back

    }
};

 

posted @ 2018-05-17 13:52  約束の空  阅读(106)  评论(0)    收藏  举报