题目解析
问题描述
小U拥有一个由 0 和 1 组成的字符串,她可以最多进行 kk 次相邻字符交换操作。目标是通过这些操作,使字符串的字典序尽可能小。
字典序的定义是:在从左到右逐字符比较两个字符串时,越早遇到较小字符的字符串字典序越小。
解题思路
核心思想
目标是将 0 尽可能移动到字符串的左侧,但每个 0 的移动需要尽量利用有限的 kk 次操作。
贪心策略
- 逐个处理每个
0:从左到右遍历字符串,找到每个0的位置。 - 计算可移动距离:对于第 i 个
0:- 统计它与前面的
1之间的距离。 - 如果距离超过剩余的 k,则只能移动 k 步。
- 统计它与前面的
- 实际移动操作:
- 将
0向左移动所能达到的位置,更新字符串和剩余的 kk 值。
- 将
- 提前结束:如果 k 耗尽,直接终止操作。
代码实现
def solution(n: int, k: int, s: str) -> str:
# 将字符串转换为列表,方便操作
s = list(s)
# 从左到右遍历字符串,找到每个 '0' 并尽量向左移动
for i in range(n):
if s[i] == '0':
# 初始化可以移动的步数
move_steps = 0
# 计算这个 '0' 前有多少个连续的 '1' 可以交换
for j in range(i - 1, -1, -1):
if s[j] == '1':
move_steps += 1
else:
break
# 实际可以移动的步数是 move_steps 和 k 的最小值
steps = min(move_steps, k)
# 如果可以移动,则移动
if steps > 0:
# 移动 '0' 并更新字符串
s[i], s[i - steps] = s[i - steps], s[i]
# 减少操作次数
k -= steps
# 如果操作次数已经用尽,直接结束
if k == 0:
break
# 返回结果
return ''.join(s)
# 测试样例
if __name__ == '__main__':
print(solution(5, 2, "01010") == '00101') # 输出: '00101'
print(solution(7, 3, "1101001") == '0110101') # 输出: '0110101'
print(solution(4, 1, "1001") == '0101') # 输出: '0101'
样例解析
样例1
输入:n=5,k=2,s="01010" 操作过程:
- 初始字符串:
01010- 第一个
0在位置 1,与前面1的距离为 1,移动 1 步:00110。 - 第二个
0在位置 3,与前面1的距离为 1,移动 1 步:00101。
- 第一个
- 剩余 k=0,操作结束。
输出:00101。
样例2
输入:n=7,k=3,s="1101001"
操作过程:
- 初始字符串:
1101001- 第一个
0在位置 2,与前面1的距离为 2,移动 2 步:1011001。 - 第二个
0在位置 4,与前面1的距离为 1,移动 1 步:0110101。
- 第一个
- 剩余 k=0,操作结束。
输出:0110101。
样例3
输入:n=4,k=1,s="1001"
操作过程:
- 初始字符串:
1001- 第一个
0在位置 1,与前面1的距离为 1,移动 1 步:0101。
- 第一个
- 剩余 k=0,操作结束。
输出:0101。
复杂度分析
-
时间复杂度:
- 外层循环遍历每个字符,复杂度为 O(n)。
- 内层计算
0前面的1,最坏情况下需要 O(n)。 - 总复杂度为 O(n^2)。
-
空间复杂度:
- 转换为列表存储字符串,复杂度为 O(n)。
优化思路
在内层遍历时,可以通过维护一个前缀数组记录每个位置前面的 1 数量,减少重复计算,优化为 O(n)。