题目解析
题目描述
小U拥有一个由0和1组成的字符串。她可以进行最多 k 次操作,每次操作可以交换相邻的两个字符。目标是通过这些操作,使得最终得到的字符串字典序最小。
例如,当前有字符串 "01010",且最多允许 2 次相邻字符交换。小U通过这 2 次交换操作,可以将字符串调整为 "00101",这是可以通过不超过 2 次操作得到的字典序最小的字符串。
现在,小U想知道,经过最多 k 次操作后,能够得到的字典序最小的字符串是什么。
输入输出格式
- 输入:三个参数:一个整数
n表示字符串的长度,一个整数k表示最多可进行的交换次数,一个字符串s由0和1组成。 - 输出:返回一个字符串,表示经过最多
k次操作后得到的字典序最小的字符串。
示例
示例1
输入:
n = 5, k = 2, s = "01010"
输出:
'00101'
解释:经过最多 2 次交换操作,字典序最小的字符串是 "00101"。
示例2
输入:
n = 7, k = 3, s = "1101001"
输出:
'0110101'
解释:经过最多 3 次交换操作,字典序最小的字符串是 "0110101"。
示例3
输入:
n = 4, k = 1, s = "1001"
输出:
'0101'
解释:经过最多 1 次交换操作,字典序最小的字符串是 "0101"。
思路分析
为了得到字典序最小的字符串,我们的目标是将字符串中尽可能多的 0 移到前面,尽量减少 1 出现的位置。每次可以交换相邻的字符,因此我们可以从左到右遍历字符串,并尽可能将 1 后面的 0 移到前面。每次移动都要检查剩余的交换次数 k 是否足够。
解题步骤
- 遍历字符串:从左到右扫描每个字符。
- 尝试将
0移到前面:对于每个1,我们尽可能将它后面的0移到它前面,直到交换次数用完或者无法再交换。 - 交换操作:每次交换都要检查是否还剩余可用的交换次数
k,并减少k。 - 输出结果:最终输出经过最多
k次交换后的字符串。
代码实现
def solution(n: int, k: int, s: str) -> str:
s = list(s) # 将字符串转换为列表以便进行交换操作
for i in range(n):
if s[i] == '1':
# 找到 '1' 后,尝试将其向前移动
j = i
while j > 0 and k > 0 and s[j-1] == '0':
# 交换 s[j] 和 s[j-1]
s[j], s[j-1] = s[j-1], s[j]
j -= 1
k -= 1
if k == 0:
break
return ''.join(s)
思路说明
- 转换为列表:首先将字符串转换为列表,因为字符串是不可变的,使用列表可以方便地交换字符。
- 从左到右遍历:我们从左到右遍历每个字符,如果遇到
'1',就尝试将它后面的'0'向前交换。每次交换时,都减少可用的交换次数k。 - 交换相邻元素:如果当前字符是
'1',且其前一个字符是'0',并且还有剩余的交换次数,则交换这两个字符,直到k次操作用完或无法交换为止。 - 字符串拼接:最终将列表转换回字符串并返回。
时间复杂度
- 时间复杂度:
O(n * k),其中n是字符串的长度,k是最大交换次数。在最坏情况下,我们需要逐个字符检查每次交换是否可行,导致复杂度为O(n * k)。 - 空间复杂度:
O(n),因为我们将字符串转换为列表以便进行交换操作。
边界情况
- 如果
k为 0,说明不能进行任何交换,直接返回原始字符串。 - 如果字符串已经是字典序最小的,不需要进行任何操作,直接返回原始字符串。
- 如果所有字符都是
0或1,则字符串本身已经是最优字典序。
通过上述思路和代码,我们能够高效地计算出经过最多 k 次操作后得到的字典序最小的字符串。