今天遇到一道有趣的LeetCode题目(编号1888),要求计算使二进制字符串变成交替字符串所需的最少反转次数。这类字符串操作问题在实际开发中其实很常见,比如数据校验、协议解析等场景都会遇到类似需求。
题目给定一个二进制字符串s(仅包含'0'和'1'),我们可以选择任意位置的字符进行反转('0'变'1'或'1'变'0')。目标是让字符串变成交替字符串,即相邻字符不相同。例如"0101"或"1010"都是合法的交替字符串。
最直观的想法是枚举所有可能的交替字符串模式,然后计算每个模式需要的最小反转次数。对于长度为n的字符串,只有两种可能的交替模式:
对于每种模式,我们可以逐个字符比较,统计需要反转的次数。最后取两种模式中的较小值即可。
时间复杂度:O(n),需要遍历字符串两次(每种模式一次)
空间复杂度:O(1),只需要常数空间存储计数
虽然暴力解法已经足够高效,但我们还可以进一步优化:
python复制def minFlips(s: str) -> int:
n = len(s)
# 计算两种模式需要的反转次数
diff1 = 0 # 0101...模式
diff2 = 0 # 1010...模式
for i in range(n):
expected = '0' if i % 2 == 0 else '1'
if s[i] != expected:
diff1 += 1
for i in range(n):
expected = '1' if i % 2 == 0 else '0'
if s[i] != expected:
diff2 += 1
return min(diff1, diff2)
python复制def minFlips(s: str) -> int:
n = len(s)
# 只需要计算一种模式
diff = 0
for i in range(n):
expected = '0' if i % 2 == 0 else '1'
if s[i] != expected:
diff += 1
return min(diff, n - diff)
题目允许对字符串进行循环旋转操作。这意味着我们可以将字符串的前k个字符移动到末尾。这种情况下,我们需要找到所有可能的旋转位置k,计算每种情况下的最小反转次数。
对于长度为n的字符串s,我们可以将其视为s+s,然后使用滑动窗口技术:
python复制def minFlips(s: str) -> int:
n = len(s)
target = '01' * n
diff = 0
min_diff = float('inf')
# 初始窗口
for i in range(n):
if s[i] != target[i]:
diff += 1
min_diff = min(diff, n - diff)
# 滑动窗口
for i in range(n):
# 移出字符
if s[i] != target[i]:
diff -= 1
# 移入字符
if s[i] != target[i + n]:
diff += 1
min_diff = min(min_diff, diff, n - diff)
return min_diff
简单情况:
需要旋转的情况:
边界情况:
这类字符串操作问题在实际开发中有多种应用:
注意:在实际实现时,要注意Python中字符串是不可变的,频繁修改会带来性能问题。建议先转换为列表处理,最后再转回字符串。
这道题看似简单,但包含了几个重要的编程思维:
在实际解决时,我最初只考虑了非旋转情况,后来才意识到需要处理循环旋转。这提醒我在读题时要更加仔细,全面考虑所有可能的操作。