838.推多米诺
838.推多米诺
题解
两种解法,模拟和BFS
模拟:
可以把字符串分成很多区间
L…L
R…L
R…R
L…R
不难看出L…L和R…R的时候就是把中间的.变成L或R,而R…L就是中间相互推,而L…R不用改变,那么问题就变成了找.左右的非.,具体看代码注释
BFS:
不难看出每一次多米诺排都与上一次有关,那么就是BFS了,把L或者R的排入队,并记录他们的入队的时间和对应的方向,在BFS的时候出队,对影响的下一张牌进行入队即可,具体看代码注释
代码
package main import ( "bytes" "fmt" ) func pushDominoes1(dominoes string) string { ans := []byte(dominoes) i, n := 0, len(ans) left, right := byte('L'), byte('R') //这里初始默认左边界为左L for i < n { j := i for j < n && ans[j] == '.' { //找出第一个非.的下标 j++ } if j < n { right = ans[j] //不是边界就是原来的值 } else { right = byte('R') //如果是边界则为R } if left == right { //L...L R...R,这种情况中间的.全都是L或者R for i < j { ans[i] = right i++ } } else if left == 'R' && right == 'L' { //R...L,这种情况的就依次推 k := j - 1 for i < k { ans[i] = 'R' ans[k] = 'L' i++ k-- } } else { //L...R,这种情况啥事都不用干 } left = right //把下一次情况的左状态赋值为这一次情况的右状态 i = j + 1 //ans[j]肯定是非. ,所以下一次要用j+1处开始检索 fmt.Println(string(ans)) } return string(ans) } func pushDominoes2(dominoes string) string { queue := make([]int, 0) time := make([]int, len(dominoes)) ans := bytes.Repeat([]byte("."), len(dominoes)) state := make([][]byte, len(dominoes)) for i := range time { time[i] = -1 } for i, ch := range dominoes { //初始 if ch != '.' { queue = append(queue, i) time[i] = 0 state[i] = append(state[i], byte(ch)) } } for len(queue) > 0 { idx := queue[0] queue = queue[1:] if len(state[idx]) > 1 { continue //说明同时收到左右两个力,即就是.,出队列即可 } LorR := state[idx][0] ans[idx] = LorR //受到一个力,则赋值,下面对idx影响的下一个进行入队 nextIdx := 0 if LorR == byte('L') { nextIdx = idx - 1 } else { nextIdx = idx + 1 } if nextIdx >= 0 && nextIdx < len(dominoes) { t := time[idx] if time[nextIdx] == -1 { //如果第一次进入,加入队列 queue = append(queue, nextIdx) time[nextIdx] = t + 1 state[nextIdx] = append(state[nextIdx], LorR) } else if time[nextIdx] == t+1 { //如果不是第一个进入,说明受到了两个力,之前入过队,并且时间也记录了 state[nextIdx] = append(state[nextIdx], LorR) } } } return string(ans) }