青训营刷题记录 多米诺骨牌均衡状态

70 阅读7分钟

多米诺骨牌均衡状态

问题描述

小S玩起了多米诺骨牌,他排列了一行骨牌,并可能将某些骨牌向左或向右推倒。随着骨牌的连锁反应,某些骨牌可能因为左右两侧受力平衡而保持竖立。现在,小S想知道在所有动作完成后,哪些骨牌保持竖立。

给定一个表示骨牌初始状态的字符串,其中:

  • 'L' 表示该位置的骨牌将向左倒。
  • 'R' 表示该位置的骨牌将向右倒。
  • '.' 表示该位置的骨牌初始时保持竖立。

模拟整个骨牌倒下的过程,求出最终保持竖立的骨牌的数目和位置。

解题思路

这道题的关键是理解如何通过模拟多米诺骨牌的倒下过程来找出保持竖立的骨牌。通过设置两个数组 tt1,分别记录向右倒和向左倒的状态,我们可以判断每个位置的骨牌最终是倒下还是保持竖立。

  1. 模拟过程

    • t[i] 用来记录从左到右的推倒情况。如果当前骨牌是 . 且前一个骨牌是 R 或前一个骨牌倒下的标记为正数(说明之前已经有骨牌向右倒),则当前骨牌也会向右倒。
    • t1[i] 用来记录从右到左的推倒情况。如果当前骨牌是 . 且后一个骨牌是 L 或后一个骨牌倒下的标记为负数(说明之后已经有骨牌向左倒),则当前骨牌也会向左倒。
  2. 平衡判断

    • t[i]t1[i] 的和为 0 时,表示该位置的骨牌保持竖立(即向右倒和向左倒的作用相互抵消)。
  3. 输出

    • 最后统计保持竖立的骨牌,并返回它们的位置。

代码实现

java
複製程式碼
public class Main {
    public static String solution(int num, String data) {
        int[] t = new int[num];  // 记录向右倒的情况
        int[] t1 = new int[num]; // 记录向左倒的情况
        StringBuffer sb = new StringBuffer(data);

        // 从左到右遍历,更新 t 数组
        for (int i = 1; i < num; i++) {
            if ((sb.charAt(i - 1) == 'R' && sb.charAt(i) == '.') || (t[i - 1] > 0 && sb.charAt(i) == '.')) {
                t[i] = t[i - 1] + 1;
            }
        }

        // 从右到左遍历,更新 t1 数组
        for (int i = num - 2; i >= 0; i--) {
            if ((sb.charAt(i + 1) == 'L' && sb.charAt(i) == '.') || (t1[i + 1] < 0 && sb.charAt(i) == '.')) {
                t1[i] = t1[i + 1] - 1;
            }
        }

        // 统计并构建输出
        StringBuffer s1 = new StringBuffer();
        int sum = 0;
        for (int i = 0; i < num; i++) {
            if (sb.charAt(i) == '.' && t[i] + t1[i] == 0) {
                s1.append(i + 1).append(',');
                sum++;
            }
        }

        // 构建结果
        StringBuffer s2 = new StringBuffer();
        s2.append(sum).append(':').append(s1);
        s2.deleteCharAt(s2.length() - 1);  // 删除最后一个逗号
        return s2.toString();
    }

    public static void main(String[] args) {
        // 测试用例
        System.out.println(solution(14, ".L.R...LR..L..")); // 4:3,4,13,14
        System.out.println(solution(5, "R...."));          // 0:
        System.out.println(solution(1, "."));              // 1:1
    }
}

代码解析

  1. 数组 tt1

    • t[i] 表示从左到右推倒的影响。正值表示右倒,t[i] > 0 表示当前骨牌会向右倒。
    • t1[i] 表示从右到左推倒的影响。负值表示左倒,t1[i] < 0 表示当前骨牌会向左倒。
  2. 左到右循环

    • 如果当前骨牌是 . 且前一个骨牌是 R,或者前一个骨牌的状态指示已向右倒,则当前骨牌的状态应该更新为向右倒(t[i] = t[i - 1] + 1)。
  3. 右到左循环

    • 如果当前骨牌是 . 且后一个骨牌是 L,或者后一个骨牌的状态指示已向左倒,则当前骨牌的状态应该更新为向左倒(t1[i] = t1[i + 1] - 1)。
  4. 平衡状态判断

    • 只有当 t[i] + t1[i] == 0 时,说明该骨牌平衡,最终会保持竖立。
  5. 输出格式

    • 最后输出保持竖立的骨牌的个数和它们的位置。位置是从 1 开始计算的,而不是数组下标。

时间复杂度

  • 本算法的时间复杂度为 O(n),其中 n 是骨牌的数量。我们只进行了两次遍历,分别计算了向右倒和向左倒的影响,因此是线性时间复杂度。

小结

这道题考察了如何模拟多米诺骨牌的倒下过程并分析其平衡状态。通过引入 tt1 两个数组,我们可以有效地追踪骨牌的倒下方向,并判断哪些骨牌会保持竖立。最终通过合适的输出格式,我们得到了正确的答案。## 多米诺骨牌均衡状态

问题描述

小S玩起了多米诺骨牌,他排列了一行骨牌,并可能将某些骨牌向左或向右推倒。随着骨牌的连锁反应,某些骨牌可能因为左右两侧受力平衡而保持竖立。现在,小S想知道在所有动作完成后,哪些骨牌保持竖立。

给定一个表示骨牌初始状态的字符串,其中:

  • 'L' 表示该位置的骨牌将向左倒。
  • 'R' 表示该位置的骨牌将向右倒。
  • '.' 表示该位置的骨牌初始时保持竖立。

模拟整个骨牌倒下的过程,求出最终保持竖立的骨牌的数目和位置。

解题思路

这道题的关键是理解如何通过模拟多米诺骨牌的倒下过程来找出保持竖立的骨牌。通过设置两个数组 tt1,分别记录向右倒和向左倒的状态,我们可以判断每个位置的骨牌最终是倒下还是保持竖立。

  1. 模拟过程

    • t[i] 用来记录从左到右的推倒情况。如果当前骨牌是 . 且前一个骨牌是 R 或前一个骨牌倒下的标记为正数(说明之前已经有骨牌向右倒),则当前骨牌也会向右倒。
    • t1[i] 用来记录从右到左的推倒情况。如果当前骨牌是 . 且后一个骨牌是 L 或后一个骨牌倒下的标记为负数(说明之后已经有骨牌向左倒),则当前骨牌也会向左倒。
  2. 平衡判断

    • t[i]t1[i] 的和为 0 时,表示该位置的骨牌保持竖立(即向右倒和向左倒的作用相互抵消)。
  3. 输出

    • 最后统计保持竖立的骨牌,并返回它们的位置。

代码实现

java
複製程式碼
public class Main {
    public static String solution(int num, String data) {
        int[] t = new int[num];  // 记录向右倒的情况
        int[] t1 = new int[num]; // 记录向左倒的情况
        StringBuffer sb = new StringBuffer(data);

        // 从左到右遍历,更新 t 数组
        for (int i = 1; i < num; i++) {
            if ((sb.charAt(i - 1) == 'R' && sb.charAt(i) == '.') || (t[i - 1] > 0 && sb.charAt(i) == '.')) {
                t[i] = t[i - 1] + 1;
            }
        }

        // 从右到左遍历,更新 t1 数组
        for (int i = num - 2; i >= 0; i--) {
            if ((sb.charAt(i + 1) == 'L' && sb.charAt(i) == '.') || (t1[i + 1] < 0 && sb.charAt(i) == '.')) {
                t1[i] = t1[i + 1] - 1;
            }
        }

        // 统计并构建输出
        StringBuffer s1 = new StringBuffer();
        int sum = 0;
        for (int i = 0; i < num; i++) {
            if (sb.charAt(i) == '.' && t[i] + t1[i] == 0) {
                s1.append(i + 1).append(',');
                sum++;
            }
        }

        // 构建结果
        StringBuffer s2 = new StringBuffer();
        s2.append(sum).append(':').append(s1);
        s2.deleteCharAt(s2.length() - 1);  // 删除最后一个逗号
        return s2.toString();
    }

    public static void main(String[] args) {
        // 测试用例
        System.out.println(solution(14, ".L.R...LR..L..")); // 4:3,4,13,14
        System.out.println(solution(5, "R...."));          // 0:
        System.out.println(solution(1, "."));              // 1:1
    }
}

代码解析

  1. 数组 tt1

    • t[i] 表示从左到右推倒的影响。正值表示右倒,t[i] > 0 表示当前骨牌会向右倒。
    • t1[i] 表示从右到左推倒的影响。负值表示左倒,t1[i] < 0 表示当前骨牌会向左倒。
  2. 左到右循环

    • 如果当前骨牌是 . 且前一个骨牌是 R,或者前一个骨牌的状态指示已向右倒,则当前骨牌的状态应该更新为向右倒(t[i] = t[i - 1] + 1)。
  3. 右到左循环

    • 如果当前骨牌是 . 且后一个骨牌是 L,或者后一个骨牌的状态指示已向左倒,则当前骨牌的状态应该更新为向左倒(t1[i] = t1[i + 1] - 1)。
  4. 平衡状态判断

    • 只有当 t[i] + t1[i] == 0 时,说明该骨牌平衡,最终会保持竖立。
  5. 输出格式

    • 最后输出保持竖立的骨牌的个数和它们的位置。位置是从 1 开始计算的,而不是数组下标。

时间复杂度

  • 本算法的时间复杂度为 O(n),其中 n 是骨牌的数量。我们只进行了两次遍历,分别计算了向右倒和向左倒的影响,因此是线性时间复杂度。

小结

这道题考察了如何模拟多米诺骨牌的倒下过程并分析其平衡状态。通过引入 tt1 两个数组,我们可以有效地追踪骨牌的倒下方向,并判断哪些骨牌会保持竖立。最终通过合适的输出格式,我们得到了正确的答案。