字符串转换挑战:在有限操作次数内将字符串 s 转变成 t
题目描述
给定两个字符串 s 和 t,以及一个操作次数上限 k,目标是在 不超过 k 次操作 的情况下,将字符串 s 转变成字符串 t。
每次操作有以下规则:
- 第
i次操作(1 <= i <= k)可以选择字符串s中 之前未被操作过 的任意一个字符位置j(1-based 下标),对该位置的字符进行切换操作。 - 切换操作含义是将字符切换 i 次,即在字母表中将该字符向后移动
i个字母,字母表循环连接:z后接a。 - 也可以选择不操作。
注意:
- 每个位置的字符最多只能被操作一次。
- 需要判断是否能在
k次操作内完成转换。
解题分析
这道题看起来非常特殊,因为每次操作的“切换次数”跟操作的顺序紧密相关:第 i 次操作必须切换 i 次字符。我们无法随意选择切换次数,只能和当前操作次数对应。
关键点:
- 字符变化由
s[i]转到t[i]的距离决定,记为d = (ord(t[i]) - ord(s[i])) % 26。 - 字符必须通过一次操作完成,且这次操作的编号
i需要满足i % 26 == d,因为切换操作是环绕字母表的。 - 每个差值
d可能会出现多次,我们需要安排足够多的操作次数满足所有相同差值的字符变化。 - 每个位置只能操作一次,意味着不能重复使用同一次操作编号。
解题方法
核心思路
- 计算字符差值
对 s 和 t 逐字符计算差值 d,即:
d = (ord(t[i]) - ord(s[i])) % 26
如果 d == 0,表示该字符不需变化,跳过。
- 统计每个差值出现的次数
使用一个字典或 Counter 来统计每个差值 d 出现的频率 freq。
验证操作次数安排的可行性
因为第 i 次操作对应切换 i 次字符,且切换是模 26 的环状字母表,所有满足条件的 i 必须满足:
因此,对于频率为 freq 的差值 d,操作次数 i 可以依次为:
即第一个满足 d 的操作是 d,第二个是 d+26,依此类推。
判断最大所需操作编号是否超过 k
如果最大操作编号:
对所有差值都成立,则可以在 k 次操作内完成转换。
代码实现
from collections import Counter
class Solution:
def canConvertString(self, s: str, t: str, k: int) -> bool:
if len(s) != len(t):
return False
diff_counter = Counter()
for i in range(len(s)):
d = (ord(t[i]) - ord(s[i])) % 26
if d != 0:
diff_counter[d] += 1
for d, freq in diff_counter.items():
max_time_needed = d + 26 * (freq - 1)
if max_time_needed > k:
return False
return True
思路分析与比较
- 暴力搜索法:考虑所有可能的操作顺序和选择,复杂度极高,不可行。
- 贪心 + 数学分析:本题关键在于理解每次操作“切换次数”的唯一性及循环性质。利用模运算关系和计数,贪心分配满足条件的操作编号,达到最优解。
- 复杂度:遍历字符串 O(n),统计次数 O(n),判断 O(26),整体为 O(n),效率高。
这种数学分析加贪心策略解决了问题的约束条件和操作唯一性。
示例说明
示例 1
s = "aab"
t = "bbb"
k = 27
- 对每个字符计算差值
d:
-
a→b,d = 1a→b,d = 1b→b,d = 0,不需变化
- 差值统计:
{1: 2} - 最大操作编号:
1 + 26 * (2 - 1) = 1 + 26 = 27 <= k,符合条件,返回True。
示例 2
s = "input"
t = "ouput"
k = 9
- 差值计算(简化示意):
位置 1 (i): i → o 差值较大,超过9,无法完成
- 在有限的9次操作内无法覆盖大差值,返回
False。
总结
这道题虽然规则复杂,但通过数学分析,利用模运算周期性和计数分配思想,可以快速判断是否能完成转换。
关键点是理解:
- 每次操作必须使用对应的切换次数
i, - 字符切换次数与操作编号的模26关系,
- 每个差值操作的编号必须分散开(相差26)。
这也是算法中常见的周期性调度与计数应用的经典案例。
930

被折叠的 条评论
为什么被折叠?



