957. Prison Cells After N Days
题解
从题目描述看出,总共有8个牢房。n的大小是n^9,如果O(n)的时间复杂度会超时。
由于每个牢房的状态只有0或者1,所以8个牢房总共的状态只有256个,因此可以预见,在牢房转换的过程中,一定会出现循环。
问题在于,循环起始位置和结束位置是不固定的,所以我们假设起始位置是loop_start,结束位置是loop_end,那么最后的状态分两种情况,n < loop_start,则直接返回对应状态,如果n >= loop_start,则从循环状态中找到对应的状态,。
我们通过两个hash表记录每个状态出现的位置,和每个位置对应的状态。
代码
小知识点,循环从loop_start开始,loop_end结束,n的转态为:
if (n < loop_start) {
return n;
} else {
return loop_start + (n - loop_start) % (loop_end - loop_start);
}
class Solution {
public:
// 数组转换为数字
int get_num(vector<int> &cells) {
int n = 0;
for (int i = 0; i < cells.size(); i ++) {
n = n*2 + cells[i];
}
return n;
}
// 状态转换
void transform(vector<int>& cells) {
vector<int> tmp = cells;
cells[0] = 0, cells[cells.size() - 1] = 0;
for (int i = 1; i < cells.size() - 1; i ++) {
if (tmp[i - 1] == tmp[i + 1]) {
cells[i] = 1;
} else {
cells[i] = 0;
}
}
}
vector<int> prisonAfterNDays(vector<int>& cells, int n) {
unordered_map<int, int> order;
unordered_map<int, vector<int>> hash;
int loop_start = -1, loop_end = -1;
for (int i = 1; i <= 256; i ++) {
transform(cells);
int n = get_num(cells);
if (order.count(n)) {
// 当有循环出现时,记录loop_start和loop_end
loop_end = i;
loop_start = order[n];
break;
} else {
// 记录状态n的位置为i
order[n] = i;
// 记录位置i的状态是cells
hash[i] = cells;
}
}
if (n < loop_start) {
return hash[n];
}
return hash[loop_start + (n - loop_start) % (loop_end - loop_start)];
}
};