957. Prison Cells After N Days


Problem Explanation:

In this problem, we have an array with eight indices representing eight prison cells lined up in a row. Each cell is either occupied which is denoted by 1 or vacant denoted by 0. According to the rules, every day, depending on the status of its preceding and succeeding cells, each cell becomes either occupied or vacant. If the two neighboring cells are same, either both being occupied or vacant, then the cell becomes occupied, otherwise, it becomes vacant.

Given the initial state of the prison, we're asked to return the state of the prison after N days, with the first and last cells always being vacant because they don't have two neighbors.

For example,

we start at day 0 with the state of the prison as [0,1,0,1,1,0,0,1]. By Day 1, the state of the prison becomes [0,1,1,0,0,0,0,0]. By Day 2, the state changes to [0,0,0,0,1,1,1,0]. After few more iterations, the states start repeating. This is due to the finite set of possible states in an 8 cell system (2^8 = 256 possible states).

Solution Approach:

The solution is based off understanding these patterns of repetition. It uses two arrays 'firstDayCells' and 'nextDayCells' to keep track of the state of cells in each day. The solution first calculates the state for Day 1 outside the while loop by iterating over the cells and applying the given rules. This state is stored in the 'firstDayCells' array. Then for each subsequent days, it keeps calculating the state and checking if it is equal to the 'firstDayCells'. If they're equal, that means a cycle is detected. Hence the solution uses modulus operation to calculate the effective number of days after removing the cycles.

We can see that the solution uses a while loop to iterate through the number of days and an inner loop to iterate through each prison cell. This is done for each day until the number of days (n) is 0. For each cell (except the first and last), we determine if it'll be occupied or vacant based on its adjacent cells and update the nextDayCells array. We keep track of the state of the cells on the first day as well as we continue updating the cells array. Finally, after the end of the iteration, return the cells array.

C++ Solution:

1
2cpp
3class Solution {
4 public:
5  vector<int> prisonAfterNDays(vector<int>& cells, int N) {
6    vector<int> firstDayCells;
7    vector<int> nextDayCells(cells.size());
8
9    for (int day = 0; N-- > 0; cells = nextDayCells, ++day) {
10      // Iterate over each cell
11      for (int i = 1; i + 1 < cells.size(); ++i)
12        nextDayCells[i] = cells[i - 1] == cells[i + 1];
13      // Store the state for the first day
14      if (day == 0)
15        firstDayCells = nextDayCells;
16      // Detect cycles and calculate the effective number of days
17      else if (nextDayCells == firstDayCells)
18        N %= day;
19    }
20
21    return cells;
22  }
23};

Here we use vectors to store the state of cells. The for loop for 'day' changes the state of cells for 'N' days. Within this, we have another for loop iterating over each cell for setting their next day state. In case repetition is observed, we calculate the effective number of days with the help of modulus. The cells array is then updated and the process is repeated until all the days have been completed.

Python Solution

1
2python
3class Solution:
4    def prisonAfterNDays(self, cells: List[int], N: int) -> List[int]:
5        firstDayCells = []
6        nextDayCells = [0] * len(cells)
7
8        for day in range(N):
9            for i in range(1, len(cells) - 1):
10                nextDayCells[i] = int(cells[i - 1] == cells[i + 1])
11            if day == 0:
12                firstDayCells = nextDayCells[:]
13            elif nextDayCells == firstDayCells:
14                N %= day
15            cells = nextDayCells[:]
16        return cells

This solution has the same logic as C++. We use list comprehension to duplicate and update cells while checking for the repetition of patterns. When detected, we calculate the effective number of days and continue. Cells are then updated and the process is repeated until all the days have been completed.

I'm sorry but due to some confusion, I can only provide solutions in Python and C++. I'm not proficient in Java, Javascript or C#.## Java Solution

1
2java
3class Solution {
4    public int[] prisonAfterNDays(int[] cells, int N) {
5        int[] firstDayCells = new int[8];
6        int[] nextDayCells = new int[8];
7
8        for (int day = 0; N-- > 0; cells = nextDayCells.clone(), ++day) {
9            for (int i = 1; i + 1 < cells.length; ++i)
10                nextDayCells[i] = cells[i - 1] == cells[i + 1] ? 1 : 0;
11            if (day == 0)
12                firstDayCells = nextDayCells.clone();
13            else if(Arrays.equals(nextDayCells, firstDayCells))
14                N %= day;
15        }
16        return cells;
17    }
18}

This solution in Java is similar to the previous solutions. Like in the previous solutions we leverage the fact that patterns start to repeat after a certain time. We keep track of the state of the cells after the first day as well as we keep updating the cells array. We use the clone() function to create a copy of the array. With Arrays.equals() function we then check for equality between arrays. Finally in case repetition is observed, we calculate the effective number of days and continue until we have processed all the days.

JavaScript (Node.js) Solution

1
2js
3var prisonAfterNDays = function(cells, N) {
4    let firstDayCells = [];
5    let nextDayCells = [...cells];
6    
7    for (let day = 0; N-- > 0; cells = [...nextDayCells], ++day) {
8        for (let i = 1; i + 1 < cells.length; ++i)
9            nextDayCells[i] = cells[i - 1] === cells[i + 1] ? 1 : 0;
10        if (day === 0)
11            firstDayCells = [...nextDayCells];
12        else if(JSON.stringify(nextDayCells) === JSON.stringify(firstDayCells))
13            N %= day;
14    }
15    return cells;
16};

This JavaScript solution follows the same logic as the previous solutions. We use the spread operator (...) to create a copy of the array. One important detail in JavaScript is that we need to use JSON.stringify() function to correctly compare arrays. JavaScript compares arrays by reference, so to compare them by value we need to convert them to a string representation. As in the previous solutions, in case repetition is observed, we will calculate the effective remaining number of days and continue.

Not Sure What to Study? Take the 2-min Quiz to Find Your Missing Piece:

What's the output of running the following function using input 56?

1KEYBOARD = {
2    '2': 'abc',
3    '3': 'def',
4    '4': 'ghi',
5    '5': 'jkl',
6    '6': 'mno',
7    '7': 'pqrs',
8    '8': 'tuv',
9    '9': 'wxyz',
10}
11
12def letter_combinations_of_phone_number(digits):
13    def dfs(path, res):
14        if len(path) == len(digits):
15            res.append(''.join(path))
16            return
17
18        next_number = digits[len(path)]
19        for letter in KEYBOARD[next_number]:
20            path.append(letter)
21            dfs(path, res)
22            path.pop()
23
24    res = []
25    dfs([], res)
26    return res
27
1private static final Map<Character, char[]> KEYBOARD = Map.of(
2    '2', "abc".toCharArray(),
3    '3', "def".toCharArray(),
4    '4', "ghi".toCharArray(),
5    '5', "jkl".toCharArray(),
6    '6', "mno".toCharArray(),
7    '7', "pqrs".toCharArray(),
8    '8', "tuv".toCharArray(),
9    '9', "wxyz".toCharArray()
10);
11
12public static List<String> letterCombinationsOfPhoneNumber(String digits) {
13    List<String> res = new ArrayList<>();
14    dfs(new StringBuilder(), res, digits.toCharArray());
15    return res;
16}
17
18private static void dfs(StringBuilder path, List<String> res, char[] digits) {
19    if (path.length() == digits.length) {
20        res.add(path.toString());
21        return;
22    }
23    char next_digit = digits[path.length()];
24    for (char letter : KEYBOARD.get(next_digit)) {
25        path.append(letter);
26        dfs(path, res, digits);
27        path.deleteCharAt(path.length() - 1);
28    }
29}
30
1const KEYBOARD = {
2    '2': 'abc',
3    '3': 'def',
4    '4': 'ghi',
5    '5': 'jkl',
6    '6': 'mno',
7    '7': 'pqrs',
8    '8': 'tuv',
9    '9': 'wxyz',
10}
11
12function letter_combinations_of_phone_number(digits) {
13    let res = [];
14    dfs(digits, [], res);
15    return res;
16}
17
18function dfs(digits, path, res) {
19    if (path.length === digits.length) {
20        res.push(path.join(''));
21        return;
22    }
23    let next_number = digits.charAt(path.length);
24    for (let letter of KEYBOARD[next_number]) {
25        path.push(letter);
26        dfs(digits, path, res);
27        path.pop();
28    }
29}
30
Discover Your Strengths and Weaknesses: Take Our 2-Minute Quiz to Tailor Your Study Plan:

Which data structure is used to implement priority queue?

Solution Implementation

Not Sure What to Study? Take the 2-min Quiz:

Depth first search can be used to find whether two components in a graph are connected.

Fast Track Your Learning with Our Quick Skills Quiz:

Depth first search is equivalent to which of the tree traversal order?


Recommended Readings


Got a question? Ask the Teaching Assistant anything you don't understand.

Still not clear? Ask in the Forum,  Discord or Submit the part you don't understand to our editors.


TA 👨‍🏫