问题分析与解题思路
给定一个由0和1组成的字符串,要求我们通过最多k次相邻字符交换操作,使得最终得到的字符串字典序最小。字典序最小的字符串通常要求将所有的0尽量放到字符串的最前面,因为在字典序中,0的值小于1。因此,我们的目标是通过交换,尽可能地将0推到前面,形成字典序最小的字符串。
字典序与交换
在这道题中,字典序最小的字符串具有以下特点:
- 尽量把所有的0移动到字符串的最前面:字典序最小的字符串应当让所有的
0尽量靠近字符串的开头,而将1尽量向后推。 - 每次交换只能交换相邻字符:每次操作只能交换相邻的字符,这限制了我们只能逐步地调整字符串的顺序。
- 交换次数有限制:我们最多可以进行
k次交换操作,因此我们需要合理利用每次交换的机会。
解题思路
- 将字符串转化为列表:因为字符串是不可变的,而我们需要在原字符串上进行交换操作,所以首先将字符串转化为列表。
- 遍历字符串并进行交换:我们需要遍历字符串中的每一个字符,遇到
0时,尽可能将它交换到前面,以使得字典序最小。 - 每次交换的条件:当我们遇到
0时,尽量将它与前面的1交换。每交换一次,k减去1,直到k次交换用完为止。如果剩余交换次数为零,则停止交换。 - 优化交换过程:为了避免不必要的交换,我们只在
0左边有1的情况下进行交换。每次交换都会让0往左移动,这样可以在尽量少的交换次数内调整字符串。
具体实现
我们实现的策略是,从左到右遍历字符串中的每个字符,遇到0时尝试将它交换到前面,直到交换次数k用尽。每次遇到0时,判断它前面是否有1,如果有且k还有剩余,就交换这两个字符,直到不能再交换为止。
代码实现
def solution(n: int, k: int, s: str) -> str:
s = list(s) # 转换为列表以便进行交换
for i in range(n):
if s[i] == '0':
j = i
while j > 0 and k > 0 and s[j - 1] == '1':
# 交换相邻字符
s[j], s[j - 1] = s[j - 1], s[j]
j -= 1
k -= 1
return ''.join(s)
if __name__ == '__main__':
print(solution(5, 2, "01010") == '00101')
print(solution(7, 3, "1101001") == '0110101')
print(solution(4, 1, "1001") == '0101')
代码解析
- 转换字符串为列表:
s = list(s),由于字符串是不可变的,我们需要将字符串转换为列表,这样我们可以在列表中修改字符。 - 遍历字符串:
for i in range(n),我们遍历字符串中的每个字符。每当遇到一个0时,尝试将其交换到前面。 - 交换条件:
while j > 0 and k > 0 and s[j - 1] == '1',如果当前字符是0,且前面有1并且k还有剩余,我们就交换这两个字符。每交换一次,k减去1,直到k用完或没有更多的交换机会。 - 返回结果:
''.join(s),最后将字符列表重新连接成字符串并返回。
时间与空间复杂度
时间复杂度:O(n),我们遍历一次字符串,检查每个字符,并进行最多k次交换操作。每次交换的时间复杂度为常数,因此总的时间复杂度为O(n)。
空间复杂度:O(n),我们将字符串转换成列表并进行修改,因此空间复杂度是O(n)。
总结和思考
这是我第二道困难题,虽然题目表面上看起来有一定的挑战性,但仔细分析后会发现,问题的关键在于利用贪心策略,逐步优化字符串的字典序。通过合理地控制交换次数,并结合每次交换的局部最优选择,我们可以在给定的约束条件下,轻松地得到字典序最小的结果。