目录
1. 题目描述
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.."
提示:
n == dominoes.length
1 <= n <= 10^5
dominoes[i] 为 'L'、'R' 或 '.'
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/push-dominoes
2. 解题分析
2.1 题意及示例解释
关于题意的补充说明:
最终状态的字符串仍以'L','R','.'表示,分别表示倒向左边、导向右边及保持垂直竖立。注意这与初始状态下被推向哪边的微妙区别。
另外题目描述中的“就这个问题而言,我们会认为一张正在倒下的多米诺骨牌不会对其它正在倒下或已经倒下的多米诺骨牌施加额外的力。”。。。这句话初看可能会觉得不知所云,要结合例子来看,参考如下示例1的解释。
示例1的解释:dominoes = "RR.L"。第3张牌左边的向右倒,右边的向左倒。由于来自左右的压力的平衡,所以它会保持不变。眼尖的小伙伴可能会感到异或,左边有两张向右倒的牌,右边只有一张向左倒的牌,那是不是向右的压力会大一些,会导致第3张牌向右倒呢?这时候就可以看出上面这句不知所云的话的用意了。第1张向右倒,第2张也向右倒,根据这句话的假设,第1张向右倒的牌没有向第2张向右倒的牌施加额外的力,因此也就不会向第3张牌传到压力。因此,第3张牌不会受到第1张牌的影响!因此,第3张牌会保持不动。
示例2的解释:dominoes = ".L.R...LR..L.."。第1张受第2张的影响向左倒,第3张不受影响,第4张向右倒导致第5张也向右倒,第8张向左倒导致第7张也向左倒,但是第6张受到左右两边的压力保持平衡不变,。。。余者类推
2.2 要点
根据上面的分析,我们可以看出这个问题的要点在于初始受力为'.'的牌。对于每一张牌:
case1: 如果它的初始受力不为'.',则它的最终状态与最初受力方向相同
case2: 如果它的初始受力为'.',则看左右最近的非'.'的牌:
case2-1: 如果两边最近的非'.'的牌为同一个受力方向,则最终状态必为这个方向
case2-2: 如果两边最近的非'.'的牌为不同方向,但是左边为向左倒,右边为向右倒,则该张牌不会受到影响,因此最终状态为保持竖立不变
case2-3: 如果两边最近的非'.'的牌为不同方向,且左边为向右倒,右边为向左倒,其最终状态于与两边非'.'牌的距离:两边距离相等则保持竖立,不等的话,与较近的那个受力方向相同。
2.3 算法思路
从头到尾遍历整个牌序列,确定每个由两张初始受力非'.'的牌分隔的区间,然后根据以上规则逐张决定该区间内的每张初始受力为'.'的牌的初始状态。
用begin和end分别表示每个区间左边牌的初始受力,end表示右边牌的初始受力,还必须记忆对应的牌序号用于计算距离。
由于是从左到右遍历,所以begin被初始化为'L'。搜索找到的第一张非'.'的牌为第一个区间的end。每次处理完一个区间后,end赋给begin然后再继续搜索下一个end。。。遍历完所有牌后最后将end赋值为'R',用于最后一个区间的处理--这样方便于将确定区间内最终状态的处理封装为一个函数实现规整化的处理。
3. 代码实现
class Solution:
def pushDominoes(self, dominoes: str) -> str:
d_list = list(dominoes)
print(d_list)
begin = tuple(('L', -1))
end = None
def finalState(begin,end):
print('finalState: ',begin,end)
if end[0] == begin[0]:
for k in range(begin[1]+1,end[1]):
d_list[k] = begin[0]
elif begin[0] == 'R' and end[0] == 'L':
for k in range(begin[1]+1,end[1]):
if (k-begin[1]) < (end[1]-k):
d_list[k] = 'R'
elif (k-begin[1]) > (end[1]-k):
d_list[k] = 'L'
# else: keep unchanged.
# else: keep unchanged.
for k in range(len(d_list)):
if d_list[k] != '.':
print(k,d_list)
end = tuple((d_list[k], k))
# Decide the final state of the segment between the current begin and end
finalState(begin,end)
begin = end
if begin[1] < len(d_list) - 1:
end = ('R', len(d_list))
finalState(begin,end)
return ''.join(d_list)
if __name__ == '__main__':
sln = Solution()
dominoes = "RR.L"
print(sln.pushDominoes(dominoes))
dominoes = ".L.R...LR..L.."
print(sln.pushDominoes(dominoes))