【Leetcode】957. Prison Cells After N Days

题目地址:

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

给定一个长度是 8 8 8 0 − 1 0-1 01数组 A A A,对于每个 i i i,如果 A [ i − 1 ] = A [ i + 1 ] A[i-1]=A[i+1] A[i1]=A[i+1],那么下一天 A [ i ] A[i] A[i]就会变成 1 1 1,否则其会变成 0 0 0。问过了 N N N天之后 A A A会变成什么样。对于 A [ 0 ] A[0] A[0] A [ 7 ] A[7] A[7],由于其只有一个邻居,所以规定过了一天它们就会变为 0 0 0

可以用个 8 8 8位整数的二进制位来表示这个数组。设当前状态是s,那么过了一天之后,状态就变为了~((s << 1) ^ (s >> 1)) & 0X7E,后面要与上0X7E是为了将首尾清零。由于一共最多有 2 8 = 256 2^8=256 28=256种状态(事实上由于过了一天 A [ 0 ] A[0] A[0] A [ 7 ] A[7] A[7]两个位置都是 0 0 0了,其实没有这么多),所以过了足够多天之后,一定会产生循环。如果还没来得及产生循环的时候就到了第 N N N天,那么可以直接返回答案。否则的话,我们可以缓存一下每个状态是第几天到达的(初始状态视为是第 0 0 0天到达的),一旦发现了循环,算出循环节长度 l l l,并查缓存得出循环节开始状态是第几天(设为是第 c c c天。循环节开始状态的意思是,第一次发现的之前访问过的状态),那么答案就是第 ( N − c ) m o d    l + c (N-c)\mod l+c (Nc)modl+c天的状态,再查一下缓存看一下那一天状态是什么,返回之即可。代码如下:

import java.util.Arrays;

public class Solution {
    public int[] prisonAfterNDays(int[] cells, int N) {
        int[] cache = new int[1 << 8];
        Arrays.fill(cache, -1);
        
        // 求出初始状态
        int cur = 0;
        for (int i = 7; i >= 0; i--) {
            if (cells[i] == 1) {
                cur |= 1 << (7 - i);
            }
        }
        // 初始状态视为是第0天
        cache[cur] = 0;
        
        // len存循环节长度
        int len = 0;
        for (int i = 1; i <= N; i++) {
        	// 算出第i天的状态
            cur = ~((cur << 1) ^ (cur >> 1)) & 0X7E;
            // 如果第i天的状态之前访问过,那么得出循环节长度
            if (cache[cur] != -1) {
                len = i - cache[cur];
                break;
            } else {
            	// 否则记录一下第一次访问到cur这个状态是第几天
                cache[cur] = i;
            }
        }
        
        // 如果循环节长度是0,意味着还没产生循环,直接返回cur对应的状态
        if (len == 0) {
            return get(cur);
        }
        
        // 否则cache[cur]就是循环节开始的天数,我们算一下第N天的状态等价于第几天的状态
        int idx = (N - cache[cur]) % len + cache[cur];
        // 找到那天的状态并返回
        for (int i = 0; i < 1 << 8; i++) {
            if (cache[i] == idx) {
                return get(i);
            }
        }
        
        return null;
    }
    
    private int[] get(int cur) {
        int[] res = new int[8];
        int idx = 7;
        while (cur != 0) {
            res[idx--] = cur & 1;
            cur >>= 1;
        }
        
        return res;
    }
}

时空复杂度 O ( 1 ) O(1) O(1)

你可能感兴趣的:(LC,二分,位运算与数学,leetcode,java)