问题描述
小C和小U在一场激烈的回文博弈中展开对决。游戏从一个初始字符串s开始,规则如下:
- 每个玩家轮流行动,每次行动都可以重新排列字符串。
- 如果通过重新排列能够形成一个回文串,游戏立即结束,当前玩家获胜。
- 如果无法形成回文串,玩家必须删除字符串中的一个字符,游戏继续。
小C总是先手,两人都使用最优策略,最终谁将赢得这场比赛呢?如果小C获胜则输出"C",小U获胜则输出"U"
测试样例
样例1:
输入:
s = "aab"
输出:'C'
样例2:
输入:
s = "abc"
输出:'C'
样例3:
输入:
s = "abcd"
输出:'U'
这道题的核心在于判断能否通过重新排列形成回文串。我们可以通过字符频率来判断一个字符串是否能重新排列成回文串。回文串有以下特点:
- 如果字符串的长度是偶数,那么每个字符必须出现偶数次。
- 如果字符串的长度是奇数,最多允许有一个字符出现奇数次,其他字符必须出现偶数次。
因此,我们可以通过统计字符串中每个字符的频率,来判断当前字符串是否能重新排列成回文串。
在游戏中,玩家的策略会依赖于能否在当前的回合中通过删除字符来使得字符串能变成回文串。具体来说,如果玩家发现当前字符串已经能重新排列成回文串,那么他就能立刻获胜。如果不能,他就需要删除一个字符,继续游戏。
分析
- 小C先手,若初始字符串能排列成回文,C直接获胜。如果不能,则每轮削减一个字符直到形成回文串。
- 游戏的关键是判断剩余字符串的字符频率分布情况。每次删除一个字符,都会影响频率的分布,而频率的变化会影响能否构成回文串。
游戏中的关键点:
- 如果字符串的字符频率中,最多只有一个字符的频率是奇数,那么这个字符串可以重新排列成回文串。
- 玩家每次删除一个字符,改变字符串的字符频率,从而影响是否能变成回文串。
解决策略
- 统计字符出现的频率。
- 计算出现奇数次的字符个数。
- 如果初始时,奇数个数大于 1,玩家必须逐步减少奇数个数直到它变为 0 或 1。
- 基于奇数个数的多少,判断谁会获胜。
具体算法:
- 统计字符串中的字符频率。
- 计算频率为奇数的字符的个数。
- 如果奇数个数大于 1,小C可以通过删除字符来改变奇数个数,最终达到 1 或 0,形成回文串。玩家轮流操作,直到达成回文。
代码实现:
from collections import Counter
def solution(s: str) -> str:
# 统计字符频率
freq = Counter(s)
# 统计出现奇数次的字符的个数
odd_count = sum(1 for count in freq.values() if count % 2 == 1)
# 如果奇数个数大于 1,玩家轮流减少奇数个数
# 如果奇数个数为0或1,意味着已经可以构成回文,小C直接获胜
if odd_count == 0 or odd_count % 2 == 1:
return "C"
else:
return "U"
# 测试
if __name__ == '__main__':
print(solution("aab") == 'C') # 小C可以直接排列成回文
print(solution("abc") == 'C') # 小C可以通过删除字符 'b' 获胜
print(solution("abcd") == 'U') # 小C无法通过一轮删字符获胜,最终小U获胜
解释:
- 我们通过
Counter(s)来统计字符串s中每个字符的出现频率。 - 然后,我们计算出出现奇数次的字符的个数
odd_count。 - 如果
odd_count为 0 或 1,意味着当前字符串可以直接排列成回文串,因此小C直接获胜。 - 如果
odd_count大于 1,那么游戏进入轮流删除字符的阶段。每删除一个字符,odd_count会减少 1。由于小C先手,若odd_count为偶数,则最终轮到小U获胜;若为奇数,则最终小C获胜。