leetcode957. N 天后的牢房(java-14天周期优化)

文章介绍了LeetCode上的一个问题957,关于模拟监狱牢房在N天后状态变化的算法。利用异或运算来解决相邻牢房状态转移的问题,揭示了状态变化的14天周期性。给出了解题思路和Java代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

leetcode957. N 天后的牢房

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/prison-cells-after-n-days

题目描述

监狱中 8 间牢房排成一排,每间牢房可能被占用或空置。
每天,无论牢房是被占用或空置,都会根据以下规则进行变更:
如果一间牢房的两个相邻的房间都被占用或都是空的,那么该牢房就会被占用。
否则,它就会被空置。
注意:由于监狱中的牢房排成一行,所以行中的第一个和最后一个牢房不存在两个相邻的房间。
给你一个整数数组 cells ,用于表示牢房的初始状态:如果第 i 间牢房被占用,则 cell[i]==1,否则 cell[i]==0 。另给你一个整数 n 。
请你返回 n 天后监狱的状况(即,按上文描述进行 n 次变更)。

示例 1:
输入: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 <= 109

解题思路

讲解这个题之前先复习下二进制算法的异或算法:
1 ^ 0 = 1
0 ^ 1 = 1
1 ^ 1 = 0
0 ^ 0 = 0
推论: 0 ^ N = N ,N ^ N = 0 (N 代表整数)
当我们看到相邻的房间同时为0 或者同时为1 时,第二天是满的,也即是1,有没有想到用异或算法.
同时为0 或者 1 异或后还是0,再和1异或,就是1了,
如果相邻的两个房间是一个空的一个满的,那异或后就是1,再和1异或后,就是0了,
所以推出状态转移公式为:
i 和 j 代表天数和房间
DP[i][j] = DP[i-1][j-1] ^ DP[i-1][j+1] ^ 1(if 0<j<6),
DP[i][j] = 0 (if j0 or j7)

寻找周期
从第一天到第N天,第1个房间和第8个房间永远为闲置状态(状态为0)
设8个房间的第1天的状态为:s1, s2, s3, s4, s5, s6, s7, s8
那么接下来第1~N天,最左边的s1和最后边的s8永远是0
第1天状态为:0, s2, s3, s4, s5, s6, s7, 0
第2天第2个房间的状态为:0s31 = s3^1
第3天第3个房间的状态为:s31s3s51^1 = (s3s3)1s5(1^1) = 01s5^0 = s5^1

在这里插入图片描述
由推导可知,每14天为1个循环周期

Java 代码演示

    /**
     * N 天后的房间
     * @param cells
     * @param n
     * @return
     */
    public int[] prisonAfterNDays(int[] cells, int n) {
        //14 天一个周期,求余
        n = n % 14;
        //刚好整除时,代表最后一天
        if (n == 0){
            n = 14;
        }
        //记录下一天的情况,
        int[] newList = new int[cells.length];
        for (int day = 0;day < n;day++ ){
            for (int i = 1; i < cells.length - 1;i++){
                newList[i] = cells[i - 1] ^ cells[i + 1] ^ 1;
            }
            //把下一天的情况拷贝回去,进行下一次的判断
            cells = deepCopyList(newList);
        }
        return newList;
    }

    /**
     * 拷贝数组
     * @param cells
     * @return
     */
    private  int[] deepCopyList(int[]cells) {
       int[] newList = new int[cells.length];
       for (int i = 0; i < cells.length;i++){
           newList[i] = cells[i];
       }
        return newList;
    }

算法专题

leetcode464. 我能赢吗

leetcode97. 交错字符串

leetcode474. 一和零

leetcode583. 两个字符串的删除操作

leetcode514. 自由之路

leetcode72. 编辑距离

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值