[LeetCode] 957. Prison Cells After N Days N天后的牢房



There are 8 prison cells in a row, and each cell is either occupied or vacant.

Each day, whether the cell is occupied or vacant changes according to the following rules:

  • If a cell has two adjacent neighbors that are both occupied or both vacant, then the cell becomes occupied.
  • Otherwise, it becomes vacant.

(Note that because the prison is a row, the first and the last cells in the row can't have two adjacent neighbors.)

We describe the current state of the prison in the following way: cells[i] == 1 if the i-th cell is occupied, else cells[i] == 0.

Given the initial state of the prison, return the state of the prison after N days (and N such changes described above.)

Example 1:

Input: cells = [0,1,0,1,1,0,0,1], N = 7
Output: [0,0,1,1,0,0,0,0]
Explanation: The following table summarizes the state of the prison on each day:
Day 0: [0, 1, 0, 1, 1, 0, 0, 1]
Day 1: [0, 1, 1, 0, 0, 0, 0, 0]
Day 2: [0, 0, 0, 0, 1, 1, 1, 0]
Day 3: [0, 1, 1, 0, 0, 1, 0, 0]
Day 4: [0, 0, 0, 0, 0, 1, 0, 0]
Day 5: [0, 1, 1, 1, 0, 1, 0, 0]
Day 6: [0, 0, 1, 0, 1, 1, 0, 0]
Day 7: [0, 0, 1, 1, 0, 0, 0, 0]

Example 2:

Input: cells = [1,0,0,1,0,0,1,0], N = 1000000000
Output: [0,0,1,1,1,1,1,0]

Note:

  1. cells.length == 8
  2. cells[i] is in {0, 1}
  3. 1 <= N <= 10^9

這道題給了一個只由0和1構成的數組,數組長度固定為8,現在要進行N步變換,變換的規則是若一個位置的左右兩邊的數字相同,則該位置的數字變為1,反之則變為0,讓求N步變換后的數組的狀態。需要注意的數組的開頭和結尾的兩個位置,由於一個沒有左邊,一個沒有右邊,默認其左右兩邊的數字不相等,所以不管首尾數字初始的時候是啥,在第一次變換之后一定會是0,而且一直會保持0的狀態。博主最開始做的時候,看題目標記的是 Medium,心想應該不需要啥特別的技巧,於是就寫了一個暴力破解的,但是超時了 Time Limit Exceeded。給了一個超級大的N,不得不讓博主懷疑是否能夠直接遍歷N,又看到了本題的標簽是 Hash Table,說明了數組的狀態可能是會有重復的,就是說可能是有一個周期循環的,這樣就完全沒有必要每次都算一遍。正確的做法的應該是建立狀態和當前N值的映射,一旦當前計算出的狀態在 HashMap 中出現了,說明周期找到了,這樣就可以通過取余來快速的縮小N值。為了使用 HashMap 而不是 TreeMap,這里首先將數組變為字符串,然后開始循環N,將當前狀態映射為 N-1,然后新建了一個長度為8,且都是0的字符串。更新的時候不用考慮首尾兩個位置,因為前面說了,首尾兩個位置一定會變為0。更新完成了后,便在 HashMap 查找這個狀態是否出現過,是的話算出周期,然后N對周期取余。最后再把狀態字符串轉為數組即可,參見代碼如下:


解法一:

class Solution {
public:
    vector<int> prisonAfterNDays(vector<int>& cells, int N) {
        vector<int> res;
        string str;
        for (int num : cells) str += to_string(num);
        unordered_map<string, int> m;
        while (N > 0) {
            m[str] = N--;
            string cur(8, '0');
            for (int i = 1; i < 7; ++i) {
                cur[i] = (str[i - 1] == str[i + 1]) ? '1' : '0';
            }
            str = cur;
            if (m.count(str)) {
                N %= m[str] - N;
            }
        }
        for (char c : str) res.push_back(c - '0');
        return res;
    }
};

下面的解法使用了 TreeMap 來建立狀態數組和當前N值的映射,這樣就不用轉為字符串了,寫法是簡單了一點,但是運行速度下降了許多,不過還是在 OJ 許可的范圍之內,參見代碼如下:


解法二:

class Solution {
public:
    vector<int> prisonAfterNDays(vector<int>& cells, int N) {
        map<vector<int>, int> m;
        while (N > 0) {
            m[cells] = N--;
            vector<int> cur(8);
            for (int i = 1; i < 7; ++i) {
                cur[i] = (cells[i - 1] == cells[i + 1]) ? 1 : 0;
            }
            cells = cur;
            if (m.count(cells)) {
                N %= m[cells] - N;
            }
        }
        return cells;
    }
};

下面這種解法是看 lee215 大神的帖子 中說的這個循環周期是 1,7,或者 14,知道了這個規律后,直接可以在開頭就對N進行縮小處理,取最大的周期 14,使用 (N-1) % 14 + 1 的方法進行縮小,至於為啥不能直接對 14 取余,是因為首尾可能會初始化為1,而一旦N大於0的時候,返回的狀態首尾一定是0。為了不使得正好是 14 的倍數的N直接縮小為0,所以使用了這么個小技巧,參見代碼如下:


解法三:

class Solution {
public:
    vector<int> prisonAfterNDays(vector<int>& cells, int N) {
        for (N = (N - 1) % 14 + 1; N > 0; --N) {
            vector<int> cur(8);
            for (int i = 1; i < 7; ++i) {
                    cur[i] = (cells[i - 1] == cells[i + 1]) ? 1 : 0;
            }
            cells = cur;
        }
        return cells;
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/957


類似題目:


參考資料:

https://leetcode.com/problems/prison-cells-after-n-days/

https://leetcode.com/problems/prison-cells-after-n-days/discuss/266854/Java%3A-easy-to-understand

https://leetcode.com/problems/prison-cells-after-n-days/discuss/205684/JavaPython-Find-the-Loop-or-Mod-14


LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM