一,题目详情
1,问题描述
小U拥有一个由0和1组成的字符串,她可以进行最多k次操作,每次操作可以交换相邻的两个字符。目标是通过这些操作,使得最终得到的字符串字典序最小。
例如,小U当前有一个字符串 01010,她最多可以进行 2 次相邻字符交换操作。通过这些操作,她可以将字符串调整为 00101,这是可以通过不超过2次操作得到的字典序最小的字符串。
现在,小U想知道,经过最多k次操作后,能够得到的字典序最小的字符串是什么。
2,测试样例
样例1:
输入:n = 5, k = 2, s = "01010"
输出:'00101'
样例2:
输入:n = 7, k = 3, s = "1101001"
输出:'0110101'
样例3:
输入:n = 4, k = 1, s = "1001"
输出:'0101'
二,解题思路
1,问题分析
我们需要通过最多k次相邻交换操作,将字符串转换为字典序最小的字符串。字典序最小意味着尽可能多的0出现在前面。
2,算法策略
贪心策略:每次在当前位置i的后面最多k个位置中找到最小的字符(0),然后将其移动到i的位置,并更新剩余的k值。
具体步骤如下:
- 将字符串转换为列表,方便操作。
- 遍历每个位置i,从0到n-1: a. 确定可以查找的范围:从i到min(i + current_k, n - 1)。 b. 在这个范围内找到最小的字符及其位置。 c. 如果找到的字符小于当前字符,则将其移动到i的位置,并更新current_k。
- 当current_k用完或者遍历完成所有位置后,返回结果字符串。
3,逐步推演(以样例1为例)
输入:n = 5, k = 2, s = "01010"
初始字符串:0 1 0 1 0
步骤1:i=0,current_k=2 查找范围:0到min(0+2,4)=2 在位置0、1、2中,最小字符是0(位置0),无需移动。
步骤2:i=1,current_k=2 查找范围:1到min(1+2,4)=3 在位置1、2、3中,最小字符是0(位置2) 将位置2的0移动到位置1,需要1次交换: 字符串变为0 0 1 1 0,current_k=2-1=1
步骤3:i=2,current_k=1 查找范围:2到min(2+1,4)=3 在位置2、3中,最小字符是1(位置2),无需移动。
步骤4:i=3,current_k=1 查找范围:3到min(3+1,4)=4 在位置3、4中,最小字符是0(位置4) 将位置4的0移动到位置3,需要1次交换: 字符串变为0 0 1 0 1,current_k=1-1=0
步骤5:i=4,current_k=0,结束循环。
最终结果为00101,与预期一致。
三,代码实现
def solution(n: int, k: int, s: str) -> str:
s_list = list(s)
current_k = k
for i in range(n):
if current_k <= 0:
break
max_possible = min(i + current_k, n - 1)
min_char = s_list[i]
min_pos = i
for j in range(i + 1, max_possible + 1):
if s_list[j] < min_char:
min_char = s_list[j]
min_pos = j
if min_pos != i:
# 移动字符到i的位置
c = s_list.pop(min_pos)
s_list.insert(i, c)
current_k -= (min_pos - i)
return ''.join(s_list)
1,复杂度分析
-
时间复杂度:O(nk)
- 外层循环运行n次,内层循环每次最多运行k次
-
空间复杂度:O(n)
- 存储字符串列表
2,边界测试
if __name__ == '__main__':
# 常规测试
print(solution(5, 2, "01010") == '00101')
print(solution(7, 3, "1101001") == '0110101')
print(solution(4, 1, "1001") == '0101')
# 边界测试:k=0
print(solution(4, 0, "1001") == "1001")
# 边界测试:全0
print(solution(3, 2, "000") == "000")
# 边界测试:全1
print(solution(3, 2, "111") == "111")
# 边界测试:k大于n
print(solution(5, 10, "11011") == "01111")
四,总结
通过贪心策略,我们实现了:
- 字典序最小:每次尽可能将最小的字符移动到当前位置
- 高效的操作:在有限的k次交换内完成优化
- 普适性:适用于所有01字符串和k值
这种解法不仅高效,还易于理解和实现。当遇到“需要通过交换操作优化字符串顺序”类问题时,贪心策略往往是解决问题的关键方法。