使用 Python 解题 - 字典序最小的01字符串

71 阅读4分钟

一,题目详情

1,问题描述

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

例如,小U当前有一个字符串 01010,她最多可以进行 2 次相邻字符交换操作。通过这些操作,她可以将字符串调整为 00101,这是可以通过不超过2次操作得到的字典序最小的字符串。

现在,小U想知道,经过最多k次操作后,能够得到的字典序最小的字符串是什么。

2,测试样例

样例1:

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

输出:'00101'

样例2:

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

输出:'0110101'

样例3:

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

输出:'0101'

企业微信截图_17423031339401.png

二,解题思路

1,问题分析

我们需要通过最多k次相邻交换操作,将字符串转换为字典序最小的字符串。字典序最小意味着尽可能多的0出现在前面。

2,算法策略

贪心策略:每次在当前位置i的后面最多k个位置中找到最小的字符(0),然后将其移动到i的位置,并更新剩余的k值。

具体步骤如下:

  1. 将字符串转换为列表,方便操作。
  2. 遍历每个位置i,从0到n-1: a. 确定可以查找的范围:从i到min(i + current_k, n - 1)。 b. 在这个范围内找到最小的字符及其位置。 c. 如果找到的字符小于当前字符,则将其移动到i的位置,并更新current_k。
  3. 当current_k用完或者遍历完成所有位置后,返回结果字符串。

3,逐步推演(以样例1为例)

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

初始字符串:0 1 0 1 0

步骤1:i=0,current_k=2 查找范围:0到min(0+2,4)=2 在位置0、1、2中,最小字符是0(位置0),无需移动。

步骤2:i=1,current_k=2 查找范围:1到min(1+2,4)=3 在位置1、2、3中,最小字符是0(位置2) 将位置2的0移动到位置1,需要1次交换: 字符串变为0 0 1 1 0,current_k=2-1=1

步骤3:i=2,current_k=1 查找范围:2到min(2+1,4)=3 在位置2、3中,最小字符是1(位置2),无需移动。

步骤4:i=3,current_k=1 查找范围:3到min(3+1,4)=4 在位置3、4中,最小字符是0(位置4) 将位置4的0移动到位置3,需要1次交换: 字符串变为0 0 1 0 1,current_k=1-1=0

步骤5:i=4,current_k=0,结束循环。

最终结果为00101,与预期一致。

三,代码实现

def solution(n: int, k: int, s: str) -> str:
    s_list = list(s)
    current_k = k
    for i in range(n):
        if current_k <= 0:
            break
        max_possible = min(i + current_k, n - 1)
        min_char = s_list[i]
        min_pos = i
        for j in range(i + 1, max_possible + 1):
            if s_list[j] < min_char:
                min_char = s_list[j]
                min_pos = j
        if min_pos != i:
            # 移动字符到i的位置
            c = s_list.pop(min_pos)
            s_list.insert(i, c)
            current_k -= (min_pos - i)
    return ''.join(s_list)

1,复杂度分析

  • 时间复杂度:O(nk)

    • 外层循环运行n次,内层循环每次最多运行k次
  • 空间复杂度:O(n)

    • 存储字符串列表

2,边界测试

if __name__ == '__main__':
    # 常规测试
    print(solution(5, 2, "01010") == '00101')
    print(solution(7, 3, "1101001") == '0110101')
    print(solution(4, 1, "1001") == '0101')

    # 边界测试:k=0
    print(solution(4, 0, "1001") == "1001")

    # 边界测试:全0
    print(solution(3, 2, "000") == "000")

    # 边界测试:全1
    print(solution(3, 2, "111") == "111")

    # 边界测试:k大于n
    print(solution(5, 10, "11011") == "01111")

四,总结

通过贪心策略,我们实现了:

  1. 字典序最小:每次尽可能将最小的字符移动到当前位置
  2. 高效的操作:在有限的k次交换内完成优化
  3. 普适性:适用于所有01字符串和k值

这种解法不仅高效,还易于理解和实现。当遇到“需要通过交换操作优化字符串顺序”类问题时,贪心策略往往是解决问题的关键方法。

企业微信截图_17423031192135.png