多米诺骨牌均衡状态
多米诺骨牌均衡是我前两天刷到的一道题目,属于模拟题,比直接问字符串、数组等来的更抽象一点,它有它独特的场景,具体怎么实现需要靠我们自己分析。但是!这对于没有真实玩过多米诺骨牌的我来说,很难想象。通过刷短视频,我只知道多米诺骨牌属于“一发而动全身”型,只要动了第一块多米诺骨牌,那么接下来的所有骨牌都会一块接一块连续倒下,直到所有都倒下。
看了这道题,我才知道,如果某块多米诺骨牌夹在左右两块多米诺骨牌中间,左边的多米诺骨牌向右倒,右边的多米诺骨牌向左倒,那么最终中间的那块多米诺不会倒下!(虽然这个东西看起来像常识,但是我之前真的没有考虑到这种情况!)
题目等级:简单 (虽然我并不觉得)
题目
小S玩起了多米诺骨牌,他排列了一行骨牌,并可能将某些骨牌向左或向右推倒。随着骨牌连锁反应的进行,一些骨牌可能因为左右两侧受力平衡而保持竖立。现在小S想要知道在所有动作完成后,哪些骨牌保持竖立。给定一个表示骨牌初始状态的字符串,其中:
- "L" 表示该位置的骨牌将向左倒。
- "R" 表示该位置的骨牌将向右倒。
- "." 表示该位置的骨牌初始时保持竖立。
模拟整个骨牌倒下的过程,求出最终仍然保持竖立的骨牌的数目和位置。
有一点点小抽象。
我拿到题目的时候会有一点点无从下手,尤其是看到它给出的测试样例的时候...
题解
进入正题!
public class Main {
public static String solution(int num, String data) {
int i = 0;
int[] t = new int[num];
int[] t1 = new int[num];
StringBuffer sb = new StringBuffer(data);
for (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;
}
}
for (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();
StringBuffer s2 = new StringBuffer();
int sum = 0;
for (i = 0; i < num; i++) {
if (sb.charAt(i) == '.' && t[i] + t1[i] == 0) {
s1.append(i + 1).append(',');
sum++;
}
}
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.."));
System.out.println(solution(5, "R...."));
System.out.println(solution(1, "."));
}
}
我们使用t和t1两个数组分别记录向右倒和向左倒的次数情况。设向右倒为正值,向左倒为负值。(说白了,就是t数组中存的值大于等于0,t1数组中存的值小于等于0)
- 从前向后循环,如果当前字符为
.且前一个字符为R或当前字符为.且前一个字符的标记值大于0(也就是在前一个字符的前面已经有R),则数组t对应当前字符的位置需要以前一个位置的值为基础进行加一并且赋值给当前字符位置的t。 - 从后向前循环,如果当前字符为
.且后一个字符为L或当前字符为.且后一个字符的标记值小于0(也就是在后一个字符的后面已经有L),则数组t1对应当前字符的位置需要以后一个位置的值为基础进行减一并且赋值给当前字符位置的t1。
定义一个计数器sum,定义两个StringBuffer,s1用于存储没有倒下的多米诺骨牌的index,s2用于存储最终结果并return。
- 循环,如果当前字符为
.且t与t1对应的值相加为0(也就是向右倒与向左倒的次数相同、达到均衡),则s1进行添加元素的操作,计数器进行加一操作。 - 出循环,也就是
s1构建完后,现在就拿到了所有均衡多米诺骨牌的下标(这边需要注意,题目中的下标并不是数组的下标,而是数组下标+1),然后s2用.append()方法与deleteCharAt()方法构造答案要的输出格式。
最后将用toString()方法将StringBuffer转化为String类型return。至此,这道题就解析完成啦!
模拟测试用例
以第一个测试用例14, ".L.R...LR..L.."模拟一下代码走向。
t和t1初始化:t = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},t1 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}- 从左向右循环字符串:具体过程省略,只体现对应的i下的
t的变化
- i = 01,当前字符为
L:t = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - i = 02,当前字符为
.:t = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - i = 03,当前字符为
R:t = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - i = 04,当前字符为
.:t = {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0} - i = 05,当前字符为
.:t = {0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0} - i = 06,当前字符为
.:t = {0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0} - i = 07,当前字符为
L:t = {0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0} - i = 08,当前字符为
R:t = {0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0} - i = 09,当前字符为
.:t = {0, 0, 0, 0, 1, 2, 3, 0, 0, 1, 0, 0, 0, 0} - i = 10,当前字符为
.:t = {0, 0, 0, 0, 1, 2, 3, 0, 0, 1, 2, 0, 0, 0} - i = 11,当前字符为
L:t = {0, 0, 0, 0, 1, 2, 3, 0, 0, 1, 2, 0, 0, 0} - i = 12,当前字符为
.:t = {0, 0, 0, 0, 1, 2, 3, 0, 0, 1, 2, 0, 0, 0} - i = 13,当前字符为
.:t = {0, 0, 0, 0, 1, 2, 3, 0, 0, 1, 2, 0, 0, 0}
- 从右向左循环字符串:
- i = 12,当前字符为
.:t1 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - i = 11,当前字符为
L:t1 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - i = 10,当前字符为
.:t1 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0} - i = 09,当前字符为
.:t1 = {0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, 0, 0, 0} - i = 08,当前字符为
R:t1 = {0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, 0, 0, 0} - i = 07,当前字符为
L:t1 = {0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, 0, 0, 0} - i = 06,当前字符为
.:t1 = {0, 0, 0, 0, 0, 0, -1, 0, 0, -2, -1, 0, 0, 0} - i = 05,当前字符为
.:t1 = {0, 0, 0, 0, 0, -2, -1, 0, 0, -2, -1, 0, 0, 0} - i = 04,当前字符为
.:t1 = {0, 0, 0, 0, -3, -2, -1, 0, 0, -2, -1, 0, 0, 0} - i = 03,当前字符为
R:t1 = {0, 0, 0, 0, -3, -2, -1, 0, 0, -2, -1, 0, 0, 0} - i = 02,当前字符为
.:t1 = {0, 0, 0, 0, -3, -2, -1, 0, 0, -2, -1, 0, 0, 0} - i = 01,当前字符为
L:t1 = {0, 0, 0, 0, -3, -2, -1, 0, 0, -2, -1, 0, 0, 0} - i = 00,当前字符为
.:t1 = {-1, 0, 0, 0, -3, -2, -1, 0, 0, -2, -1, 0, 0, 0}
-
到这边,我们得到了 t = {0, 0, 0, 0, 1, 2, 3, 0, 0, 1, 2, 0, 0, 0} 和 t1 = {-1, 0, 0, 0, -3, -2, -1, 0, 0, -2, -1, 0, 0, 0}
-
当
t[i]和t1[i]相加,如果为负数,则向左倒;如果为正数,则向右倒;如果为0,则保持平衡。不难得出,当数组下标为2、5、12、13的多米诺骨牌保持平衡,也就是第3个、第4个、第13个、第14个,一共4个。 -
最后构建答案要的格式就OVER啦~
小结
分析下来似乎也还好,没有很难,重点是要理解这两个数组的含义。
又一题完美收官!下班!