这是我参与2022首次更文挑战的第22天,活动详情查看:2022首次更文挑战
题目
838. 推多米诺 - 力扣(LeetCode) (leetcode-cn.com)
解析
按照题目所给的条件,如果入参中,指定了位置i一定往左倒,那么位置i就一定是往左倒。
从这里可以看出一个条件(或者说一个假定条件):
- 某个不被拨动的牌,受到的力没有大小之分,只有方向之分。
也就是说,如果某个牌左右均受力且自身没有被拨动,那么无论左边倒了多少牌右边倒了多少牌,这个牌就是没有被拨动的。
现在所有条件都给足了,来看看如何解决这个问题。
仔细看这个问题,可以发现:
-
位置i的状态,由:
- i-1是否往右倒
- i+1是否往左倒
- 自身的拨动情况
来共同决定。
而i-1和i+1的情况,就得由这个i左边最近的往右倒的,和i+1右边最近的往左倒的来决定。
那么,可以按照给定的顺序来进行模拟:
- 如果遇到了一个R:
- 如果上一个R没有遇到一个L,说明上一个R到当前的R之间,都要被推向R。
- 否则,更新R。
- 如果遇到了一个L:
- 如果之前所有的R都被消除了,那么:从消除的地方到当前的L,都是L。
- 如果之前有没有被消除的R,那么:从那个R到当前的L,一个一个地推。
- 如果遇到了.:继续,不做任何操作。
到最后,如果还有R没有被消除,那么从那个R开始到最后,全部都变成R。
根据这个思路,可以拟出以下代码:
public String pushDominoes(String dominoes) {
char[] status = new char[dominoes.length()];
//左倒的
int lp = -1;
//右倒的
int rp = -1;
boolean findR = false;
//核心思路是:找到一个往右倒的,就从右边找一个往左倒的
for (int i = 0; i < dominoes.length(); i++) {
if(dominoes.charAt(i) == 'R'){
//往右倒--> 还是往右倒
for(int j = rp+1;findR&&j<i;j++) status[j] = 'R';
rp = i;
status[i] = 'R';
findR = true;
continue;
}
if(dominoes.charAt(i) == 'L'){
//如果形成了一个区间,那么就得往左推
status[i] = 'L';
//从上一次重置状态开始,没有再读取到R
if(!findR){
for (int i1 = Math.max(lp, 0); i1 < i; i1++) status[i1] = 'L';
} else {
//两者不重合
lp = i;
while (lp >= rp) {
if (lp == rp) status[lp] = '.';
else {
status[rp] = 'R';
status[lp] = 'L';
}
rp++;
lp--;
}
}
lp = i+1;
rp = lp;
findR = false;
continue;
}
//.的情况不足以说明任何问题
status[i] = '.';
}
//如果最后一个右倒的没有被消除
if(findR) for (int i = rp+1; i < status.length; i++) status[i] = 'R';
return new String(status);
}