算法题解:字典序最小的01字符串
问题描述
小U有一个仅包含字符 0 和 1 的字符串,且她最多可以进行 k 次相邻字符交换操作。每次交换只能交换相邻的两个字符。小U的目标是通过最多 k 次操作使得字符串字典序最小。
示例分析
-
示例 1:
- 输入:
n = 5,k = 2,s = "01010" - 输出:
"00101"
通过最多 2 次相邻字符交换,可以将字符串调整为
"00101",这是在不超过2次操作下可以得到的字典序最小的字符串。 - 输入:
-
示例 2:
- 输入:
n = 7,k = 3,s = "1101001" - 输出:
"0110101"
经过最多 3 次交换,可以得到字典序最小的字符串
"0110101"。 - 输入:
-
示例 3:
- 输入:
n = 4,k = 1,s = "1001" - 输出:
"0101"
1 次交换后得到的字典序最小字符串为
"0101"。 - 输入:
解题思路
要在有限次数的相邻字符交换内,将字符串变得字典序最小,我们可以采用贪心策略:
- 贪心思路:优先将
0尽量往左移动,同时将1往右推。 - 计算步数:对于每个
0,计算它左移到可能最左边所需的步数,如果步数不超过k,就执行该操作并更新剩余的k值。如果k不足以将该0移到目标位置,便尽量左移。 - 逐个遍历:从左至右遍历字符串中的每一个
0,对于每个0,尝试将其向左尽量多地移动。
Python 实现
以下是代码实现:
def solution(n: int, k: int, s: str) -> str:
s = list(s) # 将字符串转为列表,方便操作
pos = 0 # 记录当前0的目标位置
for i in range(n):
if s[i] == '0':
# 计算当前0要移动到pos位置需要的步数
steps = i - pos
if steps <= k:
# 如果步数在允许范围内,移动到目标位置
s.pop(i)
s.insert(pos, '0')
k -= steps
else:
# 如果步数超出k,则只能移动k步到合适的位置
s.pop(i)
s.insert(i - k, '0')
k = 0 # 用完步数
break # 没有步数,结束循环
pos += 1 # 更新目标位置为下一个0的位置
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转化为列表,并初始化pos为0,表示下一个0应该移动到的最左位置。 - 遍历字符串:
- 对于每个字符
0,计算它左移到pos位置的步数steps。 - 如果
steps小于或等于k,则执行移动,更新剩余的k。 - 如果
steps大于k,说明剩余步数不足以将0移到目标位置,则尽量移动k步,结束循环。
- 对于每个字符
- 返回结果:将列表转回字符串形式,得到最终结果。
复杂度分析
- 时间复杂度:,因为最多对每个字符进行一次检查和操作。
- 空间复杂度:,因为我们将字符串转换成了列表。
总结
这道题考察了贪心策略在有限操作次数下的应用。通过将 0 尽量向左移动,我们可以在最少的操作下得到字典序最小的字符串。