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

51 阅读3分钟

解题思路:题目希望知道所有动作完成之后,哪些骨牌可以保持竖立。遍历骨牌数组来看,首先只需关注以'.'表示的、即初始时保持竖立的骨牌,然后根据这些'.'左右两边一定骨牌的受力来判断此骨牌是否最终竖立。首先大体分成三种情况。

  1. 若'.'在一行骨牌的开头,需保证它之后的最近的骨牌不会往左倒,即当它之后的骨牌均为'.',或往后第一个不为'.'的骨牌为‘R'时可保持竖立
  2. 若'.'在一行骨牌的末尾,需保证它之前的最近的骨牌不会往右倒,即当之前骨牌均为'.',或往前第一个不为'.'的骨牌为‘L'时可保持竖立
  3. 若'.'在中间,又可进一步分为几种不同情况,具体如下:
  • L.L
  • L..
  • L.R
  • ..L
  • ...
  • ..R
  • R.L
  • R..
  • R.R;

其中第一、四,以及最后两种情况一定无法保持竖立;第三种情况由于左边骨牌向右倒,右边骨牌向左倒,第七种情况则是两边骨牌一起倒向中间,所以一定可以保持竖立。

对于第二种情况来说,当它之后的骨牌不向左倒即可保持竖立,即当它之后的骨牌均为'.',或往后第一个不为'.'的骨牌为‘R'时可保持竖立,类似1.中情况

对于第六种情况来说,当它之前的骨牌不向右倒即可保持竖立,即当之前骨牌均为'.',或往前第一个不为'.'的骨牌为‘L'时可保持竖立,类似2.中情况

而对剩余的第五情况来说,需要看此'.'骨牌两边的前缀和后缀,看两边离它最近的不为'.'的是什么骨牌,以此来决定向哪边倒,或保持竖立,具体代码如下所示。

result=[]
for i in range(num):
    if data[i]!=".":
        continue
    # .R/.L
    if i == 0:
        x = data.find("L")
        y = data.find("R")
        if (y!=-1 and y < x) or x == y:
            result.append(i+1)
    # R./L.
    elif i  == num-1:
        x = data[::-1].find("L")
        y = data[::-1].find("R")
        if (x != -1 and x < y) or x == y:
            result.append(i + 1)
    else:
        # L.R
        if data[i-1]=="L" and data[i+1]=="R":
            result.append(i+1)
        # L..
        elif data[i-1]=="L" and data[i+1]==".":
            x = data[i+1:].find("L")
            y = data[i+1:].find("R")
            # L..R
            if (x > y and y!=-1) or x == y or (x ==-1 and y!= -1):
                result.append(i + 1)
        # ..R
        elif data[i-1]=="." and data[i+1]=="R":
            x = data[0:i][::-1].find("L")
            y = data[0:i][::-1].find("R")
            # L..R
            if (x < y and (x !=-1)) or x == y or (y ==-1 and x!= -1):
                result.append(i + 1)
        # ...
        elif (data[i - 1] == "." and data[i + 1] == "."):
            str1 = data[:i-1][::-1]  # 前缀
            str2 = data[i+2:]  # 后缀
            x, y = -1, -1
            for a in range(len(str1)):
                if str1[a] != ".":
                    x = a
                    break
            for b in range(len(str2)):
                if str2[b] != ".":
                    y = b
                    break
            if x==-1 and (y==-1 or str2[y]=="R"):
                result.append(i + 1)
            elif y==-1 and (x==-1 or str1[x]=="L"):
                result.append(i + 1)
            elif x!=-1 and y != -1:
                if (x == y and str1[x] == "R" and str2[y] == "L") or (str1[x] == "L" and str2[y] == "R"):
                    result.append(i + 1)
        # R.L
        elif (data[i-1]=="R" and data[i+1]=="L"):
            result.append(i + 1)

另外,还可以考虑骨牌的倒向与两边的左右倒的骨牌的数量有关。比如若骨牌'.'左边向右倒的骨牌数量大于其右边向左倒的骨牌数量,那么此骨牌同样不会竖立,而是会向右倒。对于此种题设,...和R.L属于同类情况,一起判断。下面是额外的代码:

# 若要看.两边R/L个数来决定
# ... / R.L
 elif (data[i - 1] == "." and data[i + 1] == ".") or (data[i-1]=="R" and data[i+1]=="L"):
     nR = 0  # 前缀倒序字符串中最后一个R的位置
     nL = 0  # 后缀字符串中最后一个L的位置
     for j in range(len(str1)):
         if str1[j] == "L":
             break
         elif str1[j] == "R":
             nR = j + 1  # 更新个数
     for j in range(len(str2)):
         if str2[j] == "R":
             break
         elif str2[j] == "L":
             nL = j + 1  # 更新个数
     # print(nR,nL)
     if nR == nL:
         result.append(i + 1)