leetcode
leetcode 751 ~ 800
推多米诺

推多米诺

难度:

标签:

题目描述

n 张多米诺骨牌排成一行,将每张多米诺骨牌垂直竖立。在开始时,同时把一些多米诺骨牌向左或向右推。

每过一秒,倒向左边的多米诺骨牌会推动其左侧相邻的多米诺骨牌。同样地,倒向右边的多米诺骨牌也会推动竖立在其右侧的相邻多米诺骨牌。

如果一张垂直竖立的多米诺骨牌的两侧同时有多米诺骨牌倒下时,由于受力平衡, 该骨牌仍然保持不变。

就这个问题而言,我们会认为一张正在倒下的多米诺骨牌不会对其它正在倒下或已经倒下的多米诺骨牌施加额外的力。

给你一个字符串 dominoes 表示这一行多米诺骨牌的初始状态,其中:

  • dominoes[i] = 'L',表示第 i 张多米诺骨牌被推向左侧,
  • dominoes[i] = 'R',表示第 i 张多米诺骨牌被推向右侧,
  • dominoes[i] = '.',表示没有推动第 i 张多米诺骨牌。

返回表示最终状态的字符串。

 

示例 1:

输入:dominoes = "RR.L"
输出:"RR.L"
解释:第一张多米诺骨牌没有给第二张施加额外的力。

示例 2:

输入:dominoes = ".L.R...LR..L.."
输出:"LL.RR.LLRRLL.."

 

提示:

  • n == dominoes.length
  • 1 <= n <= 105
  • dominoes[i]'L''R''.'

代码结果

运行时间: 100 ms, 内存: 17.4 MB


/*
 * 思路:
 * 使用 Java Stream 来简化处理过程。
 * 1. 使用一个字符数组来处理字符串的变化。
 * 2. 使用两个数组 left 和 right 来记录每个位置被左侧和右侧推到的时间。
 * 3. 使用 IntStream 进行遍历,分别从左到右和从右到左填充 right 和 left 数组。
 * 4. 最后一次遍历,通过比较 left 和 right 的值来确定每个位置的最终状态。
 */
import java.util.stream.IntStream;

public class Solution {
    public String pushDominoes(String dominoes) {
        int n = dominoes.length();
        char[] result = dominoes.toCharArray();
        int[] left = new int[n];
        int[] right = new int[n];

        IntStream.range(0, n).forEach(i -> right[i] = n);
        IntStream.range(0, n).forEach(i -> {
            if (result[i] == 'R') {
                for (int j = i; j < n && result[j] != 'L'; j++) {
                    right[j] = Math.min(right[j], j - i);
                }
            }
        });

        IntStream.range(0, n).forEach(i -> left[i] = n);
        IntStream.range(0, n).forEach(i -> {
            if (result[i] == 'L') {
                for (int j = i; j >= 0 && result[j] != 'R'; j--) {
                    left[j] = Math.min(left[j], i - j);
                }
            }
        });

        IntStream.range(0, n).forEach(i -> {
            if (left[i] < right[i]) {
                result[i] = 'L';
            } else if (right[i] < left[i]) {
                result[i] = 'R';
            } else {
                result[i] = '.';
            }
        });

        return new String(result);
    }
}

解释

方法:

该题解主要通过模拟多米诺骨牌倒下的过程来解决问题。首先,将输入字符串转换为列表以便修改。接着,使用两个指针i和j来遍历列表,i是当前考虑的起始位置,j用于寻找连续的'.'的结束位置。变量left表示当前段落的左边界状态(即前一个非'.'的字符),right表示当前段落的右边界状态(即第一个非'.'的字符)。根据left和right的不同组合,有以下几种情况:1)如果两边字符相同('L'或'R'),则将中间的'.'全部改为该字符;2)如果左边是'R',右边是'L',则从两边向中间推进,直到两指针相遇或交叉,分别设置为'R'和'L';3)如果左右边界不形成推动力(如'.'或相对的'L'和'R'),则保持中间的'.'不变。在处理完所有段落后,将列表转换回字符串形式作为结果。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
题解中提到如果左右边界相同,会将中间的所有'.'改为该边界字符。这种情况下是否考虑了连续的相同边界字符后跟着'.'的情况?例如'R.....'的处理。
是的,这种情况已经被考虑在内。当左右边界字符相同时,不论是'L'或'R',中间的所有'.'都会改为与边界相同的字符。例如在'R.....'这种情况下,如果遇到右边界也是'R'(或者没有一个明确的右边界,即到达字符串末尾),所有的'.'都会被转换为'R'。这确保了多米诺的倒向与其相邻的推力方向一致。
🦆
在处理左边界为'R',右边界为'L'的情况时,为何选择将点从两边向中间填充直到指针相遇或交叉?这种方法是否能准确处理所有长度的点段?
选择从两边向中间填充是为了模拟真实情况下多米诺骨牌受到相对方向推力的影响。当左边界是'R',右边界是'L'时,两边的力会相互作用,中间的点会受到左右两边的影响。从两边向中间填充'R'和'L'可以准确地模拟这种相互作用。当两指针相遇或交叉时,这表示中间的点已经完全被左右两边的力量平衡填充,确保了模拟的准确性。这种方法能有效处理任意长度的点段,确保每个点都得到正确的处理。
🦆
题解中未详细说明如何处理边界情况,例如字符串开头和结尾是'.'的情况。在这种情况下,最终状态的'.'如何被确定?
在字符串的开头和结尾是'.'的情况下,这些'.'的最终状态将由其相邻的非'.'字符决定。如果开头的'.'没有左边界(即开头即是'.'),则这些'.'不会被任何力量推动,因此保持为'.'。同理,如果结尾的'.'没有右边界(即结尾即是'.'),这些'.'也同样保持不变。如果某一段'.'的一侧被'R'或'L'界定,那么这些'.'将会转变为相邻的字符。这样的处理确保了边界情况也能得到合理的模拟。

相关问题