多米诺骨牌倒下模拟与竖立骨牌的求解
在这篇文章中,我们将基于一个经典的编程问题来探讨如何模拟多米诺骨牌的倒下过程,并求出最终保持竖立的骨牌的位置和数量。
问题分析
小S玩起了多米诺骨牌,给定一行骨牌的初始状态,表示每个位置上骨牌的状态:
'L'表示该位置的骨牌会向左倒;'R'表示该位置的骨牌会向右倒;'.'表示该位置的骨牌初始时竖立。
任务:模拟多米诺骨牌倒下的连锁反应,并求出最终哪些骨牌保持竖立。
思路解析
-
骨牌倒下的规律:
- 向右倒的骨牌(
'R')会影响其后续的位置,直到遇到另一块向左倒的骨牌('L')为止。 - 向左倒的骨牌(
'L')会影响其前面的骨牌,直到遇到另一块向右倒的骨牌('R')为止。
- 向右倒的骨牌(
-
模拟倒下过程:
-
我们可以通过两次遍历字符串来模拟倒下的过程:
- 从左到右遍历字符串,处理所有向右倒的骨牌(
'R')。 - 从右到左遍历字符串,处理所有向左倒的骨牌(
'L')。
- 从左到右遍历字符串,处理所有向右倒的骨牌(
-
然后,检查竖立骨牌(
.)是否被左右两边的倒下力量影响。
-
-
标记骨牌的倒下状态:
- 我们可以使用一个状态数组来标记每个位置的骨牌是否最终倒下。
- 初始时,所有的骨牌状态都设置为竖立(即
None),当遍历过程中发现受到影响时,更新骨牌的状态。
-
最终判断竖立骨牌:
- 最后,对于每一个初始竖立的骨牌(即为
.的骨牌),如果它没有受到任何倒下的影响,说明它最终保持竖立。
- 最后,对于每一个初始竖立的骨牌(即为
解决步骤
-
初始化状态数组:
-
为了标记每个位置的骨牌状态,我们使用一个数组
status,其中:None表示该位置的骨牌竖立;'R'表示该位置的骨牌倒向右;'L'表示该位置的骨牌倒向左。
-
-
处理右倒的骨牌:
- 从左到右遍历字符串,当遇到
R时,表示当前骨牌向右倒,之后的骨牌(竖立的)都会受到影响。
- 从左到右遍历字符串,当遇到
-
处理左倒的骨牌:
- 从右到左遍历字符串,当遇到
L时,表示当前骨牌向左倒,之前的骨牌(竖立的)都会受到影响。
- 从右到左遍历字符串,当遇到
-
统计最终竖立的骨牌:
- 遍历字符串,检查每个竖立的骨牌是否最终保持竖立(即没有受到左右倒的影响)。
代码实现
def domino_status(s: str):
n = len(s)
# 初始化一个数组来记录每个骨牌的最终状态
status = [None] * n
# 从左到右扫描,处理右倒的情况
force = None # 记录最近的右倒
for i in range(n):
if s[i] == 'R':
force = 'R'
elif s[i] == 'L':
force = None
elif force:
status[i] = 'R'
# 从右到左扫描,处理左倒的情况
force = None # 记录最近的左倒
for i in range(n-1, -1, -1):
if s[i] == 'L':
force = 'L'
elif s[i] == 'R':
force = None
elif force:
status[i] = 'L'
# 统计竖立的骨牌(未被左右倒影响的)
standing = []
for i in range(n):
if s[i] == '.' and status[i] == None:
standing.append(i+1) # 输出时位置从1开始
# 输出竖立骨牌的数量和位置
return len(standing), standing
# 示例输入
s = "R...L"
count, positions = domino_status(s)
print(count) # 输出竖立骨牌的数量
print(positions) # 输出竖立骨牌的位置
代码详解
-
初始化状态数组:
status数组用于记录每个骨牌的最终状态。初始时,所有骨牌都处于竖立状态,即status[i] = None。
-
从左到右遍历处理右倒的情况:
- 当遇到
R时,我们标记该位置为向右倒,并继续将之后的竖立骨牌(.)标记为向右倒。直到遇到L或字符串的末尾。
- 当遇到
-
从右到左遍历处理左倒的情况:
- 当遇到
L时,我们标记该位置为向左倒,并继续将之前的竖立骨牌(.)标记为向左倒。直到遇到R或字符串的开头。
- 当遇到
-
最终判断竖立的骨牌:
- 遍历字符串,对于每个竖立的骨牌(即初始为
.的位置),如果它没有受到左右两侧倒下力量的影响(即status[i] == None),则认为该骨牌最终保持竖立。
- 遍历字符串,对于每个竖立的骨牌(即初始为
-
返回结果:
- 最终,我们返回竖立的骨牌的数量和位置(位置从1开始)。
时间复杂度
- 从左到右遍历:时间复杂度为 O(n),其中 n 是字符串的长度。
- 从右到左遍历:时间复杂度为 O(n)。
- 最终判断竖立骨牌:时间复杂度为 O(n)。
因此,整体的时间复杂度为 O(n),非常高效。
示例
输入:
s = "R...L"
输出:
2
[2, 3]
解释:
- 初始状态为
"R...L",从左到右,R会将后面的骨牌推倒,L会将前面的骨牌推倒,最后只剩下骨牌 2 和 3 保持竖立。
总结
通过模拟多米诺骨牌的倒下过程,我们可以高效地找出最终保持竖立的骨牌。通过两次遍历和简单的状态标记方法,我们能够有效地处理这种连锁反应问题。在实际应用中,这种思路同样可以扩展到更复杂的模拟问题中。