n 张多米诺骨牌排成一行,将每张多米诺骨牌垂直竖立。在开始时,同时把一些多米诺骨牌向左或向右推。
每过一秒,倒向左边的多米诺骨牌会推动其左侧相邻的多米诺骨牌。同样地,倒向右边的多米诺骨牌也会推动竖立在其右侧的相邻多米诺骨牌。
如果一张垂直竖立的多米诺骨牌的两侧同时有多米诺骨牌倒下时,由于受力平衡, 该骨牌仍然保持不变。
就这个问题而言,我们会认为一张正在倒下的多米诺骨牌不会对其它正在倒下或已经倒下的多米诺骨牌施加额外的力。
给你一个字符串 dominoes 表示这一行多米诺骨牌的初始状态,其中:
dominoes[i] = ‘L’,表示第 i 张多米诺骨牌被推向左侧,
dominoes[i] = ‘R’,表示第 i 张多米诺骨牌被推向右侧,
dominoes[i] = ‘.’,表示没有推动第 i 张多米诺骨牌。
返回表示最终状态的字符串。
示例 1:
输入:dominoes = "RR.L"
输出:"RR.L"
解释:第一张多米诺骨牌没有给第二张施加额外的力。
import java.util.ArrayDeque;
import java.util.Deque;
//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
public String pushDominoes(String dominoes) {
return doublePointer(dominoes);
}
public String bfs(String dominoes){
//将字符串转换为字符数组
char[] cs = dominoes.toCharArray();
//创建一个三元组,记录受力多米诺牌的 位置,受力时间,受力方向
int[] times = new int[cs.length];
Deque<int[]> queue = new ArrayDeque<>();
for(int i=0;i<cs.length;i++){
if(cs[i] == '.') continue;
int loc = i;
int time = 1;
int direction = cs[i]=='L'?-1:1;
queue.addFirst(new int[]{loc,time,direction});
times[i]=time;
}
while (!queue.isEmpty()){
int[] arr = queue.pollLast();
//获取三元组,进行分析
int loc = arr[0],time = arr[1],direction=arr[2];
int nextPos = loc + direction;
if(cs[loc] == '.'||nextPos<0 || nextPos>=cs.length) continue;
if(times[nextPos] == 0){
//首次受力情况下,需要入队继续处理
queue.addFirst(new int[]{nextPos,time+1,direction});
cs[nextPos]= direction==-1?'L':'R';
times[nextPos] = time+1;
}else if(times[nextPos] == time + 1){
//否则就是多次受力的情况
cs[nextPos]='.';
}
}
return new String(cs);
}
public String doublePointer(String dominoes){
//采用双指针做法
/*
从左到右寻找闭合区间,该区间左侧有一个受力点,右侧有一个受力点,期间全部为 . 或者为空
在字符串左端添加L字符,右端添加R字符作为哨兵节点。
这两个字符的添加并不会影响算法的结果,因为左侧往左倒,右侧往右倒 不会影响原有多米诺骨牌的倒向
*/
String newDominoes = 'L' + dominoes + 'R';
StringBuilder sb = new StringBuilder();
int left = 0;
for(int right=1;right<newDominoes.length();right++){
if(newDominoes.charAt(right) == '.') continue;
int mid = right - left -1 ;
//分几种情况进行讨论
// 1. 左侧与右侧相同,则期间骨牌都是一样
// 2. 左侧L,右侧R 期间骨牌保持不变
// 3. 左侧R 右侧L 期间骨牌五五开,左半部分R 右半部分L,如果是奇数个则中间骨牌站立
if(left!=0) sb.append(newDominoes.charAt(left));
char lc = newDominoes.charAt(left);
char rc = newDominoes.charAt(right);
if(lc == rc){
for(int i=0;i<mid;i++){
sb.append(lc);
}
}else if(lc=='L' && rc == 'R'){
for(int i=0;i<mid;i++){
sb.append('.');
}
}else{
for(int i=0;i<mid/2;i++){
sb.append(lc);
}
if(mid%2==1){
sb.append('.');
}
for(int i=0;i<mid/2;i++){
sb.append(rc);
}
}
left = right;
}
return sb.toString();
}
}