AI刷题记录 | 时尚圈的衣着稳定问题

74 阅读2分钟

先贴一下此题的代码(JAVA版本)

import java.util.*;

public class Main {
    
        public static int[] solution(int n, String data) {
            // 将初始状态转换为整数表示
            int currentState = 0;
            for (char c : data.toCharArray()) {
                currentState = (currentState << 1) | (c - '0');
            }
    
            // 使用集合记录已经出现过的状态
            Set<Integer> seenStates = new HashSet<>();
            seenStates.add(currentState);
            // 模拟每一天的变化
            int days = 1;
            int nextState = currentState;
            while (true) {
                // 计算下一天的状态
                for (int i = 0; i < n; i++) {
                    int left = (i == 0) ? (currentState >> (n-1))&1 : (currentState >> (i-1))&1;
                    int right = (i == n - 1) ? (currentState >> (0))&1 : (currentState >> (i+1))&1;
                    int current = (currentState >> i) & 1;
                    if (left == current && right == current) {
                        nextState ^= (1 << i); // 改变
                    }
                }
    
    
                // 检查是否达到稳定状态
                if (nextState == currentState) {
                    int fashionCount = 0;
                    for (int i = 0; i < n; i++) {
                        int left = (i == 0) ? (currentState >> (n-1))&1 : (currentState >> (i-1))&1;
                        int right = (i == n - 1) ? (currentState >> (0))&1 : (currentState >> (i+1))&1;
                        int current = (currentState >> i) & 1;
                        if (left != current && right != current) {
                            fashionCount++;
                        }
                    }
                    return new int[] { days, fashionCount };
                }
    
                // 检查新状态是否已经出现过
                if (seenStates.contains(nextState)) {
                    return new int[] { -1, -1 };
                }
                seenStates.add(nextState);
    
                // 更新当前状态
                currentState = nextState;
                days++;
            }
        }

    public static void main(String[] args) {
        // Add your test cases here
        // solution(4, "0000");
        System.out.println(java.util.Arrays.equals(solution(4, "0000"), new int[] {
        -1, -1 }));
        System.out.println(java.util.Arrays.equals(solution(4, "1110"), new int[]{2,
        4}));
    }
}

思路:

这种判断是否有环的题一般都是将已经出现的状态存储一下,然后一直计算下一状态,如果出现了已经出现过的状态,证明必定是有环的。

此题有一个比较有意思的点是,输入的状态是字符串,但是全是0和1组成的字符串,所以存入set的时候,可以想到通过二进制转化为int类型去存储(当然用字符串存也可以),因为刚好在位运算方面的知识有些薄弱,所以拿这个题练下手。

下面是代码里一些关于位运算的记录:

代码片段1

for (char c : data.toCharArray()) {
    currentState = (currentState << 1) | (c - '0');
}

这句代码的意思是,计算字符串data对应的int类型的值。实现方法是,数字不断左移然后加上新的一位(在代码里的体现是|运算符),因为

0|0 = 0
0|1 = 1

即一个数字和0作或运算,还是数字本身。

代码片段2

int left = (i == 0) ? (currentState >> (n-1))&1 : (currentState >> (i-1))&1;

先说这个三目运算符,因为n个同学围成了一个圈,所以当i==0或者当i==n-1的时候,需要对其相邻元素进行单独判断。

其次说这行代码里的位运算,currentState >> (n-1))&1这句代码的意思是,计算currentState这个int类型的值,n-1位二进制是多少(从0开始,从右往左数)。

1&0 = 0
1&1 = 1

为什么这里用与呢?因为不同于代码片段1,我们只需要保留最后一位,和1相与后,除了最后一位其他位必为0。