1 题目
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]
2 尝试解
2.1 分析
有一个长度为8的数组,按照以下规则每天进行变化:
if old[i-1]==old[i+1],new[i] = 1
else new[i] = 0
其中两个端点从第一天起就一直为0。问N天过后的数组。
将数组看做一个8bit的数,其中首位和末位为0,其余的数在0-1之间变动,则最多有2^6 = 64种情况,即该问题一定会进入一个循环。当N超过64时,可以对循环周期取余。
i从0开始,以map[i] = encode(cells)的形式记录第(i+1)天的结果,其中encode是将数组转换为8bit整数的函数。终止条件为i==N或者结果已经出现过。
如果结果出现过,此时虽然已经进入另一个循环的第一项,但是由于i从0开始,此时i就是循环周期。则第N天对应的是map[N%i]。
如果i==N,则为发现循环已经结束。第N天对应的就是结果,即map[N%i]。
2.2 代码
class Solution {
public:
int encode(vector<int>& cells){
int result = 0, multiplier = 1;
for(int i = cells.size()-1; i >=0 ; i--){
result += cells[i]*multiplier;
multiplier *= 2;
}
return result;
}
vector<int> decode(int code){
vector<int> cells(8,0);
for(int i = cells.size()-1; i>=0 ; i--){
cells[i] = code%2;
code /= 2;
}
return cells;
}
vector<int> prisonAfterNDays(vector<int>& cells, int N) {
unordered_map<int,int> cycle;
unordered_set<int> saver;
int i = 0;
for( ; i < N ; i++){
vector<int> temp(cells.size(),0);
for(int j = 1; j < temp.size()-1;j++){
temp[j] = (cells[j-1]==cells[j+1]?1:0);
}
swap(cells,temp);
int code = encode(cells);
if(saver.count(code)!=0) break;
saver.insert(code);
cycle[i] = code;
}
return decode(cycle[(N-1)%i]);
}
};
3 标准解
3.1 分析
由于前一天和后一天的结果是可以互相推出的,所以第一项也一定是循环中的一项。所以只需要判断第i天的结果与第一天是否相等即可。如果前一天的结果与后一天不能相互推出,那么可能不同的情况第二天结果相同,就无法保证前半部分也是循环的一部分。需要记录每个情况出现的时间t,如果第i天出现了相同结果,则循环周期为i-t。求结果时,N要先减去不在循环中的前半部分长度。所以上述做法其实既假设了所有项都是循环部分,又考虑了第一项不是循环部分。
3.2 代码
vector<int> prisonAfterNDays(vector<int>& c, int N) {
vector<int> f_c, next_c(c.size(), 0);
for (int cycle = 0; N-- > 0; c = next_c, ++cycle) {
for (auto i = 1; i < c.size() - 1; ++i) next_c[i] = c[i - 1] == c[i + 1];
if (cycle == 0) f_c = next_c;
else if (next_c == f_c) N %= cycle;
}
return c;
}