• leetcode957. N 天后的牢房


    8 间牢房排成一排,每间牢房不是有人住就是空着。

    每天,无论牢房是被占用或空置,都会根据以下规则进行更改:

    • 如果一间牢房的两个相邻的房间都被占用或都是空的,那么该牢房就会被占用。
    • 否则,它就会被空置。

    (请注意,由于监狱中的牢房排成一行,所以行中的第一个和最后一个房间无法有两个相邻的房间。)

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

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

    --

    思路:

      如果是按照一般思路,根据前一天状态,更新第二天状态,逻辑会很清晰,但是会超时或溢出(当N=1000000000时),因为要生成N次数组来保存状态。

      优化办法:

        1、题干是8个房间,没个房间就0或1两种状态,所以8个房间最多一共也就 2的8次方 =256种状态, 

        2、状态是有限的,而 天数N可以是无穷大的,所以规律就在这256种之内。

        3、最多生成256天的状态, 在这之内,不断寻找有无相同状态的一天,如果有,那么规律就出现了

            1. 2. [3].  . . . k .  . . . 256. . N

            加入我们算出第k天的状态,和第3天一致,那么从k之后的未来所有状态,都是处于 3到k 之间循环的。

      步骤:

        1. 添加第0天状态到 list

            2. 根据 list中的最后一天的状态pre,再添加新的一天的状态 cur

                3. 查看cur 在list 0~pre中有无重复,如果有,规律出现,返回出现的下标index,如果无 继续上述步骤

        4.  (N-index)%(k-index) + index 即为结果的下标

    //957. N 天后的牢房
        public int[] prisonAfterNDays(int[] cells, int N) {
            if (N == 0) {
                return cells;
            }
            ArrayList<int[]> list = new ArrayList<>();
            list.add(cells);
            int k = 1;  //k为第一天
            while (k <= N) {
                int[] cur = prisionStatus(list.get(k - 1));//根据昨天的状态获取今天的状态
                list.add(cur);//将今天的状态添加至list
                int index = findStatus(list);//循环判断list中是否存在已有状态,如果有返回下标,无返回-1
                if (index != -1) { //如果 index != -1 ,说明找到重复 ,   ps:此处存在 /by zero 异常
                    try {
                        int res = (N - index) % (k - index); //结果的下标
                        return list.get(index + res);
                    } catch (Exception e){
                        return list.get(index);  //存在异常的情况是 index + 1 == cur ,也就是昨天和今天状态一致,也意味着监狱状态稳定,以后不会变化。
                    }
                }
                k++;
            }
            return list.get(list.size() - 1);
        }
    
        //根据昨天获取当天监狱状态
        private int[] prisionStatus(int[] pre) {
            int[] cur = new int[pre.length];
            cur[0] = 0;
            cur[cur.length - 1] = 0;
            for (int i = 1; i < pre.length - 1; i++) {
                if (pre[i - 1] == pre[i + 1]) {
                    cur[i] = 1;
                } else {
                    cur[i] = 0;
                }
            }
            return cur;
        }
    
        //循环判断list中是否存在已有状态,如果有返回下标,无 返回-1
        private int findStatus(ArrayList<int[]> list) {
            for (int i = 0; i <= list.size() - 2; i++) {
                if (arrayIsSame(list.get(list.size() - 1), list.get(i))) {
                    return i;
                }
            }
            return -1;
        }
    
        //判断数组是否一致
        private boolean arrayIsSame(int[] a, int[] b) {
            if (a.length != b.length) {
                return false;
            }
            for (int i = 0; i < a.length; i++) {
                if (a[i] != b[i]) {
                    return false;
                }
            }
            return true;
        }
  • 相关阅读:
    [不错]A step-by-step guide to enabling security, TLS/SSL, and PKI authentication in Elasticsearch
    asp.net core 从单机到集群
    Redlock:Redis分布式锁最牛逼的实现
    es为什么要取消type? 或者为什么一个index下多个type会有问题
    reorder-list——链表、快慢指针、逆转链表、链表合并
    c 链表之 快慢指针 查找循环节点(转)
    binary-tree-preorder-traversal——前序遍历
    binary-tree-postorder-traversal——二叉树后续遍历
    insertion-sort-list——链表、插入排序、链表插入
    sort-list——链表、快慢指针找中间、归并排序
  • 原文地址:https://www.cnblogs.com/magicya/p/10126231.html
Copyright © 2020-2023  润新知