编程笔记:回文博弈 | 豆包MarsCode AI刷题

158 阅读5分钟

问题描述

小C和小U在一场激烈的回文博弈中展开对决。游戏从一个初始字符串s开始,规则如下:

  1. 每个玩家轮流行动,每次行动都可以重新排列字符串。
  2. 如果通过重新排列能够形成一个回文串,游戏立即结束,当前玩家获胜。
  3. 如果无法形成回文串,玩家必须删除字符串中的一个字符,游戏继续。

小C总是先手,两人都使用最优策略,最终谁将赢得这场比赛呢?如果小C获胜则输出"C",小U获胜则输出"U"

题目解析

问题背景: 小C和小U进行一场回文博弈游戏。给定一个初始字符串 s,每个玩家可以重新排列字符串,或者删除一个字符。若通过重新排列可以形成回文串,则该玩家获胜,否则他们删除一个字符继续游戏。小C总是先手,两人都遵循最优策略,最终谁获胜?

回文的定义:

  • 回文串是一个正着读和反着读都相同的字符串。例如,"aba""racecar" 都是回文串。

  • 要使一个字符串能够重新排列成回文串,必须满足以下条件:

    • 如果字符串的长度为偶数,那么每个字符的出现次数都必须是偶数。
    • 如果字符串的长度为奇数,那么至多只有一个字符的出现次数为奇数,其他字符的出现次数必须是偶数。

解题思路

  1. 字符频率统计:

    • 我们首先需要统计字符串中每个字符的出现次数。利用 Python 的 collections.Counter 可以非常方便地完成这一步。
  2. 奇数次数的字符数量:

    • 对于回文串,最多允许一个字符出现奇数次。因此,如果字符串中出现奇数次的字符数量大于 1,则该字符串不能直接排列成回文串。游戏将继续进行。
  3. 分析游戏进程:

    • 如果奇数次数的字符数量小于或等于 1,意味着当前字符串可以直接排列成回文串,当前玩家可以获胜。
    • 如果奇数次数的字符数量大于 1,游戏将继续,玩家需要删除字符直到满足回文的条件。此时游戏变得类似于消耗字符的博弈,最终谁能使字符串满足回文条件谁获胜。
  4. 博弈分析:

    • 如果奇数次数的字符数量大于 1,游戏的进程将会涉及到删除字符。每轮操作删除一个字符,可以看作是减少奇数次数字符的数量。
    • 先手优势:  如果剩余的奇数次数字符的数量是奇数,意味着小C(先手)会在最后一步将其减少为 1,直接获胜。若奇数次数字符的数量是偶数,则小U(后手)会在最后一步获胜。
    • 进一步的,游戏也可以通过字符串长度的奇偶性来判断:如果剩余的字符个数为奇数,小C获胜;如果为偶数,小U获胜。

代码详解

def solution(s: str) -> str:
    from collections import Counter
    
    # 计算字符频率
    char_count = Counter(s)
    
    # 计算奇数次数的字符数量
    odd_count = sum(1 for count in char_count.values() if count % 2 == 1)
    
    # 根据奇数个数判断游戏结果
    if odd_count <= 1:
        return 'C'  # 小C可以直接获胜
    else:
        # 当奇数个数大于1时,游戏就看当前字符串的长度
        # 如果剩余字符数为奇数,小C必胜;为偶数小U必胜
        return 'C' if (len(s) % 2 == 1) else 'U'

代码解析

  1. 字符频率统计:

    • 使用 Counter(s) 统计字符串中每个字符出现的次数,char_count 是一个字典,其中键是字符,值是字符出现的次数。
  2. 计算奇数次数的字符数量:

    • odd_count = sum(1 for count in char_count.values() if count % 2 == 1) 这行代码计算了所有出现次数为奇数的字符的数量。
  3. 判断是否可以直接排列成回文串:

    • 如果 odd_count <= 1,则说明当前字符串可以直接排列成回文串,因此小C(先手)获胜。
  4. 判断博弈结果:

    • 如果 odd_count > 1,说明游戏无法立即结束,玩家将逐步删除字符。此时根据剩余字符数的奇偶性来判断最终谁将获胜。
    • return 'C' if (len(s) % 2 == 1) else 'U':如果剩余字符的数量为奇数,小C必胜;若为偶数,小U必胜。

例子

  1. 例子 1: 输入:"aabb"

    • 统计字符频率:{'a': 2, 'b': 2}
    • odd_count = 0,因此可以立即排列成回文串,游戏结束,小C获胜。
  2. 例子 2: 输入:"abc"

    • 统计字符频率:{'a': 1, 'b': 1, 'c': 1}
    • odd_count = 3,游戏继续。由于剩余字符数为 3(奇数),小C获胜。
  3. 例子 3: 输入:"abcabc"

    • 统计字符频率:{'a': 2, 'b': 2, 'c': 2}
    • odd_count = 0,可以直接排列成回文串,小C获胜。

知识点总结

  1. 回文的条件:

    • 字符串能否排列成回文串依赖于字符的频率。大部分字符的频率必须为偶数,最多允许一个字符频率为奇数。
  2. 博弈论:

    • 问题的关键在于分析奇数次数的字符数量,并根据字符串的长度奇偶性判断谁能最终获胜。
  3. 使用 Counter

    • Python 的 collections.Counter 非常适合用于统计字符串中各个字符的出现次数,简化了频率统计的过程。
  4. 博弈的策略:

    • 通过奇数字符的数量以及剩余字符数的奇偶性分析博弈过程,最终得出胜者。