多米诺骨牌均衡状态| 豆包MarsCode AI刷题

128 阅读7分钟

多米诺骨牌均衡状态

问题描述

小S玩起了多米诺骨牌,他排列了一行骨牌,并可能将某些骨牌向左或向右推倒。随着骨牌连锁反应的进行,一些骨牌可能因为左右两侧受力平衡而保持竖立。现在小S想要知道在所有动作完成后,哪些骨牌保持竖立。

给定一个表示骨牌初始状态的字符串,其中:

  • "L" 表示该位置的骨牌将向左倒。
  • "R" 表示该位置的骨牌将向右倒。
  • "." 表示该位置的骨牌初始时保持竖立。

模拟整个骨牌倒下的过程,求出最终仍然保持竖立的骨牌的数目和位置。


测试样例

样例1:

输入:num = 14,data = ".L.R...LR..L.."
输出:'4:3,6,13,14'

样例2:

输入:num = 5,data = "R...."
输出:'0'

样例3:

输入:num = 1,data = "."
输出:'1:1'

思路分析

在面对这个多米诺骨牌均衡状态的问题时,我们需要深入思考如何通过一种有效的方式来模拟骨牌倒下的整个过程,并准确找出最终保持竖立的骨牌情况。这里采用了数学建模的思想来构建解决思路,具体如下:

首先,我们把骨牌的不同初始状态进行数字化的抽象表示。将 “L” 看作是本身无法被改变的且能够向左传递的 “-1”,这是因为 “L” 代表骨牌向左边倒,从某种意义上可以理解为它会给其左侧的骨牌带来一种 “向左的影响”,所以用 “-1” 来量化这种影响。同理,把 “R” 看作是本身无法被改变的且能够向右传递的 “2”,因为 “R” 表示骨牌向右边倒,会对其右侧的骨牌施加 “向右的影响”,“2” 这个值就用来体现这种特性。而 “.” 则表示初始时保持竖立的骨牌,在我们构建的模型中,将其视为 “0”,意味着它在初始阶段没有明确的向左或向右的影响传递。

当我们把输入的表示骨牌初始状态的字符串按照这样的规则转化成一个数组后,就相当于构建了一个能够反映骨牌初始影响状态的模型。接下来,随着骨牌连锁反应的进行,也就是在这个数组中进行后续的运算操作。

在经过 “R” 和 “L” 的影响传递之后形成的新数组中,元素 “0” 所对应的骨牌位置就是那些始终保持竖立的骨牌,这很好理解,因为从始至终它们都没有受到 “R” 向右的推动或者 “L” 向左的推动,所以依然保持着最初竖立的状态。而元素 “1” 所对应的骨牌位置则是那些被 “L” 和 “R” 影响后可能处于竖立状态的骨牌。但这里要注意的是,并不是所有的 “1” 所对应的骨牌最终都能保持竖立,根据题意,只有当这些 “1” 是连续奇数个时,其中间项所对应的骨牌才有可能因为左右两侧受力平衡而保持竖立;如果是连续偶数个 “1”,那么这些骨牌是无法保持竖立的。所以,我们最后的任务就是要准确统计出数组中元素为 “0” 的数目,以及符合上述要求的 “1”(即连续奇数个 “1” 的中间项所对应的骨牌)的情况,从而得出最终仍然保持竖立的骨牌的数目和位置。

代码实现


def transform_array(data):
array = [] original = [] # 用于记录每个位置原始的转化值 # 1. 将字符串转化为数组并记录原始转化值 
for char in data:
if char == '.': array.append(0) original.append(0)
elif char == 'R': array.append(2) original.append(2) 
elif char == 'L': array.append(-1) original.append(-1)

在这个部分,函数首先遍历输入的表示骨牌初始状态的字符串 data。对于字符串中的每个字符,根据其是 .R 还是 L,分别将对应的数值(0、2、-1)添加到 array 数组中,同时也将相同的数值添加到 original 数组中,用于记录每个位置最初的转化值。这样就完成了将骨牌初始状态字符串转化为可进行后续运算的数组形式,并保留了原始状态信息。

# 2. 执行所有原始转化值为2对其他元素的操作
for i, value in enumerate(array): 
if value == 2 and original[i] == 2:
for j in range(i + 1, len(array)):
if original[j] in [2, -1]:
break
elif array[j] == 0:
array[j] += 2

这里开始模拟骨牌中 R(向右倒)的影响传递过程。外层循环通过 enumerate 函数遍历 array 数组,同时获取每个元素的索引 i 和值 value。当找到 value 为 2 且其在 original 数组中对应的原始转化值也为 2 的元素时,说明找到了一个最初状态为 R 的骨牌位置。

然后进入内层循环,从该位置 i 的下一个位置 j 开始,依次检查后续的元素。如果后续元素在 original 数组中的原始转化值是 2(表示也是最初为 R 的骨牌)或者 -1(表示最初为 L 的骨牌),那么就停止当前的影响传递,因为 R 的影响遇到 R 或者 L 就不会再继续向右传递了。而如果遇到的元素在 array 数组中的值为 0(表示最初是竖立的骨牌),就将其值加上 2,这意味着该竖立骨牌受到了当前 R 骨牌向右的影响,其状态值发生了改变。

# 3. 执行所有原始转化值为-1对其他元素的操作
for i, value in enumerate(array):
if value == -1 and original[i] == -1: 
for j in range(i - 1, -1, -1): 
if original[j] == 2 or original[j] == -1: 
break 
elif array[j] == 0 or array[j] == 2:
array[j] -= 1

这里与上面同理

zero_positions = [i + 1 for i, value in enumerate(transform_array(data)) 
if value == 0] one_positions = [] consecutive_ones_count = 0 consecutive_ones_start = None

这里是最后的对0或符合要求的1的统计

for i, value in enumerate(transform_array(data)): 
if value == 1:
if consecutive_ones_start is None:
consecutive_ones_start = i
consecutive_ones_count += 1
elif consecutive_ones_count > 0:
if consecutive_ones_count % 2 == 1:
middle_index = consecutive_ones_start + consecutive_ones_count // 2 one_positions.append(middle_index + 1) consecutive_ones_start = None consecutive_ones_count = 0

这里通过一个循环再次遍历经过 transform_array 函数处理后的数组。当遇到值为 1 的元素时,如果 consecutive_ones_start 为 None,说明是连续 1 的开始,就将当前索引 i 赋值给 consecutive_ones_start,并将 consecutive_ones_count 加 1,开始记录连续 1 的情况。

当遇到值不为 1 的元素且之前已经记录了连续 1 的情况(即 consecutive_ones_count > 0)时,就需要判断这些连续 1 是否符合保持竖立的条件。如果连续 1 的个数 consecutive_ones_count 是奇数,那么根据题意,其中间项对应的骨牌可能保持竖立。通过计算中间项的索引(consecutive_ones_start 加上 consecutive_ones_count 除以 2),并将索引加 1(同样因为骨牌位置从 1 开始),将该位置添加到 one_positions 列表中。然后重置 consecutive_ones_start 和 consecutive_ones_count,准备记录下一组连续 1 的情况。

if not combined_positions:
return "0" combined_positions.sort() return f"{len(combined_positions)}:{','.join(map(str, combined_positions))}"

这个返回语句块

总结

通过这样的数学建模思路,我们能够将看似复杂的多米诺骨牌倒下及平衡的实际问题,转化为在一个数组中进行数值运算和分析的问题,为后续通过代码实现具体的计算和判断奠定了清晰的逻辑基础。