字典序最小的01字符串
问题描述
小U拥有一个由0和1组成的字符串,她可以进行最多k次操作,每次操作可以交换相邻的两个字符。目标是通过这些操作,使得最终得到的字符串字典序最小。
例如,小U当前有一个字符串 01010,她最多可以进行 2 次相邻字符交换操作。通过这些操作,她可以将字符串调整为 00101,这是可以通过不超过2次操作得到的字典序最小的字符串。
现在,小U想知道,经过最多k次操作后,能够得到的字典序最小的字符串是什么。
测试样例
样例1:
输入:
n = 5, k = 2, s = "01010"
输出:'00101'
样例2:
输入:
n = 7, k = 3, s = "1101001"
输出:'0110101'
样例3:
输入:
n = 4, k = 1, s = "1001"
输出:'0101'
题目分析
给定一个由0和1组成的字符串,小U可以通过最多进行k次相邻字符交换来使得最终字符串的字典序最小。我们的目标是利用这些操作尽可能地将字符串转换为字典序最小的形式。
字典序最小的字符串应当是所有0出现在前面,所有1出现在后面。因此,在进行操作时,我们需要尽可能地将0移到前面。
解题思路
字符串的性质:字典序最小的形式是所有0在前,所有1在后。因此,我们的目标是尽量将0移到字符串的左边。
策略:从左到右遍历字符串,对于每一个0,我们希望尽量将它交换到当前位置前面去。遇到一个0时,尽可能将它向左交换,直到达到k次交换的限制或将0移到合适的位置。
代码分析
通过最多 k 次相邻字符交换操作来将字符串 s 转换为字典序最小的字符串。
首先,将字符串转换为列表。
s = list(s)
然后使用while循环遍历字符串,每次遇到0时,尽量将它向前交换,并记录所用的交换次数。
对于每个字符位置 i,我们检查其之后最多 k 个字符(包括 i+1 到 i+k 的字符),即尝试将当前位置 i 的字符和其后面最多 k 个字符中的最小字符交换位置。
接着,判断是否能够进行这些交换,如果条件满足,使用 while 循环将字符 s[j] 向左交换到 s[i] 的位置。
处理完当前位置后,移动到下一个字符继续处理。直到处理完整个字符串或剩余的交换次数为 0 为止。
while i < n and k > 0:
for j in range(i + 1, min(i + k + 1, n)):
if s[j] < s[i]:
swap_count = j - i
if swap_count <= k:
while j > i:
s[j], s[j - 1] = s[j - 1], s[j]
j -= 1
k -= swap_count
break
i += 1
最后输出最终的字符串。
return ''.join(s)
完整代码如下:
def solution(n: int, k: int, s: str) -> str:
# write code here
s = list(s)
i = 0
while i < n and k > 0:
for j in range(i + 1, min(i + k + 1, n)):
if s[j] < s[i]:
swap_count = j - i
if swap_count <= k:
while j > i:
s[j], s[j - 1] = s[j - 1], s[j]
j -= 1
k -= swap_count
break
i += 1
return ''.join(s)
总结
这道题目本质上是一个贪心问题。我们希望通过有限的交换次数,将字符串的字典序尽可能地最小化。贪心的策略是:每次遇到一个字符时,尽可能将后面的小字符交换到当前位置。这种方法局部最优(每次选择最小字符交换到当前位置)能够帮助我们获得全局的最小字典序。
当前的算法通过 while 和 for 循环两层结构,尽可能地选择在当前字符后面最小的字符进行交换。虽然这种方法简单有效,但当 k 很大时,可能会存在一些优化空间。一个优化的思路是:在某些情况下,找到一个更高效的数据结构来帮助快速查找当前范围内的最小字符,避免重复计算。另外,避免多次相邻交换(直接将字符移动到正确位置)也可能会提高效率。