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

120 阅读3分钟

问题描述

小U拥有一个由01组成的字符串,她可以进行最多k次操作,每次操作可以交换相邻的两个字符。目标是通过这些操作,使最终的字符串字典序最小。例如:

  • 输入字符串为01010,允许最多k=2次操作,字典序最小化后结果为00101

解题思路

核心思想

使用贪心法,逐步在当前位置找到可以用有限步数内交换过来的最小字符,将其移动到当前位置,从而使字符串字典序最小:

  1. 逐位处理

    • 遍历字符串,从左到右依次处理每个字符。
    • 对于当前字符,在剩余最多k步范围内找到字典序最小的字符。
  2. 交换操作

    • 如果找到的字符不在当前位,则通过相邻交换将其移动到当前位置,消耗相应的步数。
    • 更新剩余步数 k
  3. 终止条件

    • 如果步数 k 用尽,则直接返回当前字符串。

详细步骤

  1. 将字符串转换为列表(便于操作)。

  2. 从左到右逐位处理:

    • 在当前位置 i 和可操作范围内([i+1, min(i+k+1, n)]),找到字典序最小的字符及其位置 min_pos
    • 如果 min_pos 与当前位不同,通过交换将 min_pos 的字符移动到 i 位置,并消耗相应步数 k -= (min_pos - i)
  3. 如果 k 消耗完毕,或者所有字符处理完毕,结束操作。

代码实现

def solution(n: int, k: int, s: str) -> str:
    s = list(s)  # 转换为列表,方便操作
    for i in range(n):
        if k <= 0:  # 如果没有剩余操作次数,直接结束
            break
        min_pos = i
        # 寻找当前位置到最多允许的范围内字典序最小的字符
        for j in range(i + 1, min(i + k + 1, n)):
            if s[j] < s[min_pos]:
                min_pos = j
        # 如果找到的最小字符不是当前字符,执行交换
        if min_pos != i:
            k -= (min_pos - i)  # 消耗步数
            min_char = s[min_pos]  # 记录最小字符
            # 将最小字符移动到当前位置
            for j in range(min_pos, i, -1):
                s[j] = s[j - 1]
            s[i] = min_char
    
    return ''.join(s)  # 转换为字符串返回

复杂度分析

  1. 时间复杂度:O(n * k)

    • 外层循环遍历字符串,复杂度为 O(n)。
    • 内层循环寻找最小字符的范围最多为 k,整体复杂度 O(n * k)。
  2. 空间复杂度:O(n)

    • 使用了一个列表存储字符串,空间复杂度为 O(n)。

测试用例

示例 1

  • 输入n = 5, k = 2, s = "01010"

  • 输出"00101"

  • 解释

    • 初始:01010
    • 第1步:交换10,得00110(消耗1步)。
    • 第2步:交换10,得00101(消耗1步)。

示例 2

  • 输入n = 7, k = 3, s = "1101001"

  • 输出"0110101"

  • 解释

    • 初始:1101001
    • 第1步:交换01,得1011001(消耗1步)。
    • 第2步:交换01,得0111001(消耗2步)。

示例 3

  • 输入n = 4, k = 1, s = "1001"

  • 输出"0101"

  • 解释

    • 初始:1001
    • 第1步:交换01,得0101(消耗1步)。

总结

  • 贪心策略:在每一步中,尽量找到可以用最小步数移动到当前位置的字典序最小字符。

  • 灵活调整范围:通过 min(i+k+1, n) 限制范围,保证不会超出剩余步数。

  • 优点

    • 简洁高效,充分利用有限步数。
    • 易于扩展到其他类似问题。