字节青训营题目: 字典序最小的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'

思路

如果想让结果字典序最小,就需要将字符串左侧的 "1" 尽可能右移。但有可能会遇到多个 "1" 相连的情况 (如测试样例2) , 所以就需要统一处理, 将左侧连续的 "1" 看作整体, 一起右移。

先从左遍历找到第一个1的位置, 再初始化右指针。(用于确定连续1的位置)

用剩余交换次数控制循环,每次从上一次连续1后的位置找连续1后的第一个0:

  1. 找完整个字符串都没有0,说明此时字典序已经最小了,直接结束循环即可
  2. 找到后,计算移动连续1的次数,与剩余次数比较
    • 剩余交换次数够用,则直接交换此时连续1的头尾,减少交换次数,使头尾指针均右移,准备下次循环
    • 剩余交换次数不够,说明这次只够移动一部分的连续1,那就只交换后一部分,交换完成后就是答案

完整代码附上

python是世界上最好的语言.cpp

def solution(n: int, k: int, s: str) -> str:
    s = list(s)

    # 初始化左指针
    i = 0
    # 确定第一个1的位置
    for i in range(n):
        if s[i] == "1":
            break

    # 初始化右指针
    j = i + 1
    
    while k > 0:  # 循环判读交换次数
        # 确定第一个1之后的第一个0的位置
        for j in range(j, n):
            if s[j] == "0":
                break
            elif j == n - 1:
                j += 1
                break

        # 如果右指针到达末尾,则说明已经交换完毕
        if j == n:
            k = 0
        else:  # 如果右指针与左指针之间的距离大于交换次数,则交换次数为k
            if j - i < k:
                # 交换连续1的头尾即可
                s[i] = "0"
                s[j] = "1"
                # 交换次数改变
                k -= j - i
                # 连续1的左指针右移
                i += 1
                # 连续1的右指针重置
                j += 1
            else:
                s[j - k] = "0"
                s[j] = "1"
                k = 0
    return "".join(s)
posted @ 2024-11-02 15:39  ling-yuan  阅读(17)  评论(0)    收藏  举报  来源