Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
每日刷题第72天 2021.03.31
838. 推多米诺
- leetcode原题链接:leetcode-cn.com/problems/pu…
- 难度:中等
- 方法:
题目描述
- 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.."
解题思路
- 根据题意,如果一个序列有力作用的话,应该是有三种情况,一种是全部向左,一种是全部向右,一种是处于平衡。
- 选择从左到右遍历, 我们不需要关注向左的力,因为向左的力只作用于已经遍历过的序列,所以我们只需要考虑两个状态
- 可用
flag表示这两种状态,使用num来记录目前可能会改变的序列长度。 - 具体而言,对于每一个站立的牌,使用双指针的方式寻找其左右两侧最近的被推倒的牌,有以下几种情况
- 左
L右R,中间牌未受力,全部站立.... - 左
L右L,中间牌全部向左推倒LLLL - 左
R右R,中间牌全部向右推倒RRRR - 左
R右L,中间牌前半向右,后半向左,最中间受力平衡,仍站立:RR.LL
- 左
- 解法:
l为左指针,往后遍历- 如果
dominoes[l] == 'L',此时默认前面已经处理好了,就l += 1 - 如果
dominoes[l] == '.',此时r = l + 1,往后找,如果找到dominoes[r] == 'L',就把l到r这一段全变为L,然后让l = r + 1,继续遍历;如果找到dominoes[r] == 'R',就让l = r,继续遍历 - 如果
dominoes[l] == 'R',就让r继续往后找,如果找到dominoes[r] == 'L',就可以从lr开始把遇到的变为L/R;如果找到dominoes[r] == 'R',就把l到r这一段全变为R,然后继续遍历
- 如果
AC代码
var pushDominoes = function(dominoes) {
let n = dominoes.length
let res = Array(n).fill(0)
//受力情况
let force = 0
for(let i = 0; i < n; i++){
if(dominoes[i] === "R") force = n;
else if ( dominoes[i] === "L") force = 0
else force = Math.max(force - 1, 0);
res[i] += force
}
console.log(res)
// 从右往左,碰到r,左倾力为0,碰到l,左倾力为最大值,碰到. 需要更新force,
force = 0
for(let i = n - 1; i >= 0; i--){
if(dominoes[i] === "L") force = n;
else if(dominoes[i] === "R") force = 0;
else force = Math.max(force - 1, 0);
res[i] -= force
}
console.log(res)
//最后遍历res,大于0表示右倾,小于0表示左倾,等于0 表示平衡
for(let i = 0; i < n; i++){
if(res[i] > 0) res[i] = "R";
else if( res[i] < 0) res[i] = "L";
else res[i] = "."
}
return res.join("")
};
总结
- 相类似的题目,周赛中的车相撞的题目,都是考虑思维的,不能只停留在当前相邻的两个元素身上,远处的也会作用上。