如果相邻两个颜色均相同则删除当前颜色

标签: 贪心 数学 字符串 博弈

难度: Medium

总共有 n 个颜色片段排成一列,每个颜色片段要么是 'A' 要么是 'B' 。给你一个长度为 n 的字符串 colors ,其中 colors[i] 表示第 i 个颜色片段的颜色。

Alice 和 Bob 在玩一个游戏,他们 轮流 从这个字符串中删除颜色。Alice 先手 。

  • 如果一个颜色片段为 'A' 且 相邻两个颜色 都是颜色 'A' ,那么 Alice 可以删除该颜色片段。Alice 不可以 删除任何颜色 'B' 片段。
  • 如果一个颜色片段为 'B' 且 相邻两个颜色 都是颜色 'B' ,那么 Bob 可以删除该颜色片段。Bob 不可以 删除任何颜色 'A' 片段。
  • Alice 和 Bob 不能 从字符串两端删除颜色片段。
  • 如果其中一人无法继续操作,则该玩家  掉游戏且另一玩家 获胜 。

假设 Alice 和 Bob 都采用最优策略,如果 Alice 获胜,请返回 true,否则 Bob 获胜,返回 false

示例 1:

输入:colors = "AAABABB"
输出:true
解释:
AAABABB -> AABABB
Alice 先操作。
她删除从左数第二个 'A' ,这也是唯一一个相邻颜色片段都是 'A' 的 'A' 。

现在轮到 Bob 操作。
Bob 无法执行任何操作,因为没有相邻位置都是 'B' 的颜色片段 'B' 。
因此,Alice 获胜,返回 true 。

示例 2:

输入:colors = "AA"
输出:false
解释:
Alice 先操作。
只有 2 个 'A' 且它们都在字符串的两端,所以她无法执行任何操作。
因此,Bob 获胜,返回 false 。

示例 3:

输入:colors = "ABBBBBBBAAA"
输出:false
解释:
ABBBBBBBAAA -> ABBBBBBBAA
Alice 先操作。
她唯一的选择是删除从右数起第二个 'A' 。

ABBBBBBBAA -> ABBBBBBAA
接下来轮到 Bob 操作。
他有许多选择,他可以选择任何一个 'B' 删除。

然后轮到 Alice 操作,她无法删除任何片段。
所以 Bob 获胜,返回 false 。

提示:

  • 1 <= colors.length <= 105
  • colors 只包含字母 'A' 和 'B'

Submission

运行时间: 55 ms

内存: 17.1 MB

class Solution:
    def winnerOfGame(self, colors: str) -> bool:
        lst1 = re.findall("A{3,}",colors)
        lst2 = re.findall("B{3,}",colors) 
        a , b = 0 , 0 
        for x in lst1 :
            a += len(x) - 2 
        for x in lst2 :
            b += len(x) - 2
        return a > b  
        

Explain

这个题解通过使用正则表达式来快速找出所有连续的'A'和'B'的子串,这些子串长度至少为3,因为只有这样的子串才能进行删除操作。对于每个连续的'A'子串,可以进行的删除操作数为子串长度减去2(因为连续的三个'A'中可以删除中间的一个,以此类推,每增加一个'A',就多一个可以删除的位置)。同理,这也适用于'B'。统计Alice和Bob能够删除的总数,比较两者之间的可删除次数,如果Alice的次数多于Bob,则Alice会获胜,否则Bob会获胜。

时间复杂度: O(n)

空间复杂度: O(n)

import re

class Solution:
    def winnerOfGame(self, colors: str) -> bool:
        # 使用正则表达式找出所有连续至少3个'A'的子串
        lst1 = re.findall('A{3,}', colors)
        # 使用正则表达式找出所有连续至少3个'B'的子串
        lst2 = re.findall('B{3,}', colors)
        a, b = 0, 0
        # 计算Alice可以删除的'A'的次数
        for x in lst1:
            a += len(x) - 2
        # 计算Bob可以删除的'B'的次数
        for x in lst2:
            b += len(x) - 2
        # 如果Alice的删除次数多于Bob的,则Alice获胜
        return a > b

Explore

在正则表达式中,量词`{n,m}`表示前面的元素至少出现`n`次,至多出现`m`次。当`m`被省略时,如`{3,}`,它表示前面的元素至少出现`3`次,没有上限。因此,`A{3,}`和`B{3,}`确保匹配的字符串至少包含连续的三个`A`或`B`,这正是题目要求可以进行删除操作的最小子串长度。

在这个题目中,只有当至少有三个连续的相同颜色时,才能进行删除操作,且每次操作只能删除中间的一个颜色。例如,对于子串`AAA`,只有一个中间的`A`可以被删除,因此可执行的删除操作数是`3-2=1`。如果子串是`AAAA`,则可以删除中间的两个`A`(`AA`或者`AA`),操作数是`4-2=2`。因此,对于任何长度`n`的连续子串,可执行的删除操作数总是`n-2`。

题解中通过正则表达式分别找出所有连续至少3个`A`的子串和`B`的子串,然后计算每个子串的可删除操作次数(子串长度减去2)。Alice负责删除`A`,Bob负责删除`B`。通过将Alice可以删除的`A`的总次数与Bob可以删除的`B`的总次数进行比较,如果Alice的总次数多于Bob,则Alice有优势,否则Bob有优势。

题解中的算法只考虑了初始状态下可进行的删除操作,没有考虑删除操作后可能引起的连锁反应,即新的连续子串的形成。这种简化假设可能不会影响比较Alice和Bob谁有更多的初始删除机会,但在一个真实的游戏场景中,这种连锁反应可能改变游戏结果。因此,如果要精确模拟游戏,需要一个更复杂的算法来迭代考虑每次删除后的新状态。