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的转态为:

    1. if (n < loop_start) {
    2. return n;
    3. } else {
    4. return loop_start + (n - loop_start) % (loop_end - loop_start);
    5. }
    1. class Solution {
    2. public:
    3. // 数组转换为数字
    4. int get_num(vector<int> &cells) {
    5. int n = 0;
    6. for (int i = 0; i < cells.size(); i ++) {
    7. n = n*2 + cells[i];
    8. }
    9. return n;
    10. }
    11. // 状态转换
    12. void transform(vector<int>& cells) {
    13. vector<int> tmp = cells;
    14. cells[0] = 0, cells[cells.size() - 1] = 0;
    15. for (int i = 1; i < cells.size() - 1; i ++) {
    16. if (tmp[i - 1] == tmp[i + 1]) {
    17. cells[i] = 1;
    18. } else {
    19. cells[i] = 0;
    20. }
    21. }
    22. }
    23. vector<int> prisonAfterNDays(vector<int>& cells, int n) {
    24. unordered_map<int, int> order;
    25. unordered_map<int, vector<int>> hash;
    26. int loop_start = -1, loop_end = -1;
    27. for (int i = 1; i <= 256; i ++) {
    28. transform(cells);
    29. int n = get_num(cells);
    30. if (order.count(n)) {
    31. // 当有循环出现时,记录loop_start和loop_end
    32. loop_end = i;
    33. loop_start = order[n];
    34. break;
    35. } else {
    36. // 记录状态n的位置为i
    37. order[n] = i;
    38. // 记录位置i的状态是cells
    39. hash[i] = cells;
    40. }
    41. }
    42. if (n < loop_start) {
    43. return hash[n];
    44. }
    45. return hash[loop_start + (n - loop_start) % (loop_end - loop_start)];
    46. }
    47. };