[python]字典序最小的01字符串 | 豆包MarsCode AI刷题

117 阅读3分钟

算法题解:字典序最小的01字符串

问题描述

小U有一个仅包含字符 01 的字符串,且她最多可以进行 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"

解题思路

要在有限次数的相邻字符交换内,将字符串变得字典序最小,我们可以采用贪心策略:

  1. 贪心思路:优先将 0 尽量往左移动,同时将 1 往右推。
  2. 计算步数:对于每个 0,计算它左移到可能最左边所需的步数,如果步数不超过 k,就执行该操作并更新剩余的 k 值。如果 k 不足以将该 0 移到目标位置,便尽量左移。
  3. 逐个遍历:从左至右遍历字符串中的每一个 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')

代码解析

  1. 初始化:将字符串 s 转化为列表,并初始化 pos 为0,表示下一个 0 应该移动到的最左位置。
  2. 遍历字符串
    • 对于每个字符 0,计算它左移到 pos 位置的步数 steps
    • 如果 steps 小于或等于 k,则执行移动,更新剩余的 k
    • 如果 steps 大于 k,说明剩余步数不足以将 0 移到目标位置,则尽量移动 k 步,结束循环。
  3. 返回结果:将列表转回字符串形式,得到最终结果。

复杂度分析

  • 时间复杂度O(n)O(n),因为最多对每个字符进行一次检查和操作。
  • 空间复杂度O(n)O(n),因为我们将字符串转换成了列表。

总结

这道题考察了贪心策略在有限操作次数下的应用。通过将 0 尽量向左移动,我们可以在最少的操作下得到字典序最小的字符串。