【思维题】B024_LC_N 天后的牢房(状态压缩 + 循环节)

一、Problem

8 间牢房排成一排,每间牢房不是有人住就是空着。每天,无论牢房是被占用或空置,都会根据以下规则进行更改:

如果一间牢房的两个相邻的房间都被占用或都是空的,那么该牢房就会被占用。
否则,它就会被空置。
(请注意,由于监狱中的牢房排成一行,所以行中的第一个和最后一个房间无法有两个相邻的房间。)

我们用以下方式描述监狱的当前状态:如果第 i 间牢房被占用,则 cell[i]==1,否则 cell[i]==0。

根据监狱的初始状态,在 N 天后返回监狱的状况(和上述 N 种变化)。

输入:cells = [0,1,0,1,1,0,0,1], N = 7
输出:[0,0,1,1,0,0,0,0]
解释:
下表概述了监狱每天的状况:
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]

示例 2:
输入:cells = [1,0,0,1,0,0,1,0], N = 1000000000
输出:[0,0,1,1,1,1,1,0]

提示:

cells.length == 8
cells[i] 的值为 0 或 1
1 <= N <= 10^9

二、Solution

方法一:状态压缩 + 循环节

N 很大,模拟会超时的,这种题要有解的话,一定存在循环节,这里用一个 map 存储状态与天数的映射

当某一个状态在 D1 出现过,且在后面的天数 D2 也出现了的话,就存在一个大小为 D1-D2 的循环节,D 可对循环节进行取模,进而缩小循环次数

class Solution {
public:
	int nextState(int st) {
		int nst = 0;
		for (int i = 1; i <= 6; i++) {
			if (((st>>(i-1))&1) == ((st>>(i+1))&1))
				nst |= 1 << i;
		}
		return nst;
	}
    vector<int> prisonAfterNDays(vector<int>& A, int D) {
    	int n = A.size(), st = 0; vector<int> ans(n, 0);
    	unordered_map<int, int> m;
    	for (int i = 0; i < n; i++) if (A[i])
    		st |= (1 << i);

    	while (D) {
    		if (m.count(st))
    			D %= m[st]-D;
    		m[st] = D;
    		if (D >= 1) D--, st = nextState(st);
    	}
    	for (int i = 0; i < n; i++) if ((st >> i) & 1) 
    		ans[i] = 1;
    	return ans;
    }
};

复杂度分析

  • 时间复杂度: O ( 循 环 节 大 小 ) O(循环节大小) O()
  • 空间复杂度: O ( n ) O(n) O(n)

你可能感兴趣的:(#,思维题,状态压缩,循环节)