🧠
Brute Force (Copy Board and Update)
💡 This approach uses extra memory to avoid corrupting neighbor information. It is straightforward and helps understand the problem deeply before optimizing.
Intuition
Create a copy of the board to read original states while updating the original board to the next state. This prevents interference between updates.
Algorithm
- Create a deep copy of the original board.
- For each cell, count live neighbors using the copy.
- Apply the Game of Life rules to update the original board.
- Return the updated board.
💡 The main challenge is to avoid reading updated cells when counting neighbors, which is solved by using a copy.
from copy import deepcopy
def gameOfLife(board):
m, n = len(board), len(board[0])
copy_board = deepcopy(board)
directions = [(-1,-1), (-1,0), (-1,1), (0,-1), (0,1), (1,-1), (1,0), (1,1)]
for i in range(m):
for j in range(n):
live_neighbors = 0
for dx, dy in directions:
x, y = i + dx, j + dy
if 0 <= x < m and 0 <= y < n and copy_board[x][y] == 1:
live_neighbors += 1
if copy_board[i][j] == 1:
if live_neighbors < 2 or live_neighbors > 3:
board[i][j] = 0
else:
if live_neighbors == 3:
board[i][j] = 1
# Example usage:
if __name__ == '__main__':
board = [[0,1,0],[0,0,1],[1,1,1],[0,0,0]]
gameOfLife(board)
print(board)
Line Notes
from copy import deepcopyImport deepcopy to create a full copy of the board to avoid reference issues
copy_board = deepcopy(board)Create a snapshot of the original board to read original states safely
for i in range(m):Iterate over each row to process every cell
for dx, dy in directions:Check all eight neighbors around the current cell
if 0 <= x < m and 0 <= y < n and copy_board[x][y] == 1:Count only live neighbors within bounds
if copy_board[i][j] == 1:Apply rules for live cells based on neighbor count
board[i][j] = 0Update original board cell to dead if under/overpopulation
if live_neighbors == 3:Revive dead cell if exactly three live neighbors
import java.util.Arrays;
public class GameOfLife {
public static void gameOfLife(int[][] board) {
int m = board.length, n = board[0].length;
int[][] copyBoard = new int[m][n];
for (int i = 0; i < m; i++)
copyBoard[i] = Arrays.copyOf(board[i], n);
int[][] directions = {{-1,-1}, {-1,0}, {-1,1}, {0,-1}, {0,1}, {1,-1}, {1,0}, {1,1}};
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
int liveNeighbors = 0;
for (int[] d : directions) {
int x = i + d[0], y = j + d[1];
if (x >= 0 && x < m && y >= 0 && y < n && copyBoard[x][y] == 1) {
liveNeighbors++;
}
}
if (copyBoard[i][j] == 1) {
if (liveNeighbors < 2 || liveNeighbors > 3) {
board[i][j] = 0;
}
} else {
if (liveNeighbors == 3) {
board[i][j] = 1;
}
}
}
}
}
public static void main(String[] args) {
int[][] board = {{0,1,0},{0,0,1},{1,1,1},{0,0,0}};
gameOfLife(board);
for (int[] row : board) {
System.out.println(Arrays.toString(row));
}
}
}
Line Notes
int[][] copyBoard = new int[m][n];Create a new 2D array to hold the original board state
copyBoard[i] = Arrays.copyOf(board[i], n);Copy each row to avoid referencing the original array
for (int[] d : directions)Iterate over all eight possible neighbor directions
if (x >= 0 && x < m && y >= 0 && y < n && copyBoard[x][y] == 1)Check bounds and count live neighbors safely
if (copyBoard[i][j] == 1)Apply rules for live cells based on neighbor count
board[i][j] = 0;Update original board cell to dead if conditions met
if (liveNeighbors == 3)Revive dead cell if exactly three live neighbors
#include <iostream>
#include <vector>
using namespace std;
void gameOfLife(vector<vector<int>>& board) {
int m = board.size(), n = board[0].size();
vector<vector<int>> copyBoard = board;
vector<pair<int,int>> directions = {{-1,-1}, {-1,0}, {-1,1}, {0,-1}, {0,1}, {1,-1}, {1,0}, {1,1}};
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
int liveNeighbors = 0;
for (auto d : directions) {
int x = i + d.first, y = j + d.second;
if (x >= 0 && x < m && y >= 0 && y < n && copyBoard[x][y] == 1) {
liveNeighbors++;
}
}
if (copyBoard[i][j] == 1) {
if (liveNeighbors < 2 || liveNeighbors > 3) {
board[i][j] = 0;
}
} else {
if (liveNeighbors == 3) {
board[i][j] = 1;
}
}
}
}
}
int main() {
vector<vector<int>> board = {{0,1,0},{0,0,1},{1,1,1},{0,0,0}};
gameOfLife(board);
for (auto& row : board) {
for (int cell : row) cout << cell << ' ';
cout << '\n';
}
return 0;
}
Line Notes
vector<vector<int>> copyBoard = board;Copy the board to preserve original states for neighbor checks
for (auto d : directions)Loop over all eight neighbor directions
if (x >= 0 && x < m && y >= 0 && y < n && copyBoard[x][y] == 1)Count live neighbors only if inside bounds
if (copyBoard[i][j] == 1)Apply rules for live cells based on neighbor count
board[i][j] = 0;Kill cell if underpopulation or overpopulation
if (liveNeighbors == 3)Revive dead cell if exactly three live neighbors
function gameOfLife(board) {
const m = board.length, n = board[0].length;
const copyBoard = board.map(row => row.slice());
const directions = [[-1,-1], [-1,0], [-1,1], [0,-1], [0,1], [1,-1], [1,0], [1,1]];
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
let liveNeighbors = 0;
for (const [dx, dy] of directions) {
const x = i + dx, y = j + dy;
if (x >= 0 && x < m && y >= 0 && y < n && copyBoard[x][y] === 1) {
liveNeighbors++;
}
}
if (copyBoard[i][j] === 1) {
if (liveNeighbors < 2 || liveNeighbors > 3) {
board[i][j] = 0;
}
} else {
if (liveNeighbors === 3) {
board[i][j] = 1;
}
}
}
}
}
// Example usage:
const board = [[0,1,0],[0,0,1],[1,1,1],[0,0,0]];
gameOfLife(board);
console.log(board);
Line Notes
const copyBoard = board.map(row => row.slice());Create a deep copy of the board to avoid modifying neighbor info prematurely
for (const [dx, dy] of directions)Iterate over all eight neighbors
if (x >= 0 && x < m && y >= 0 && y < n && copyBoard[x][y] === 1)Count live neighbors only if within bounds
if (copyBoard[i][j] === 1)Apply rules for live cells based on neighbor count
board[i][j] = 0;Kill cell if underpopulation or overpopulation
if (liveNeighbors === 3)Revive dead cell if exactly three live neighbors
We visit each cell once and check up to 8 neighbors, so O(m*n). The copy requires O(m*n) space.
💡 For a 100x100 board, this means about 10,000 cells processed, which is efficient but uses extra memory.
Interview Verdict: Accepted
This approach works correctly but uses extra space, which can be improved.