字符典最小子字符串题解 | 豆包MarsCode AI刷题

71 阅读4分钟

问题分析与解题思路

给定一个由01组成的字符串,要求我们通过最多k次相邻字符交换操作,使得最终得到的字符串字典序最小。字典序最小的字符串通常要求将所有的0尽量放到字符串的最前面,因为在字典序中,0的值小于1。因此,我们的目标是通过交换,尽可能地将0推到前面,形成字典序最小的字符串。

字典序与交换

在这道题中,字典序最小的字符串具有以下特点:

  1. 尽量把所有的0移动到字符串的最前面:字典序最小的字符串应当让所有的0尽量靠近字符串的开头,而将1尽量向后推。
  2. 每次交换只能交换相邻字符:每次操作只能交换相邻的字符,这限制了我们只能逐步地调整字符串的顺序。
  3. 交换次数有限制:我们最多可以进行k次交换操作,因此我们需要合理利用每次交换的机会。

解题思路

  1. 将字符串转化为列表:因为字符串是不可变的,而我们需要在原字符串上进行交换操作,所以首先将字符串转化为列表。
  2. 遍历字符串并进行交换:我们需要遍历字符串中的每一个字符,遇到0时,尽可能将它交换到前面,以使得字典序最小。
  3. 每次交换的条件:当我们遇到0时,尽量将它与前面的1交换。每交换一次,k减去1,直到k次交换用完为止。如果剩余交换次数为零,则停止交换。
  4. 优化交换过程:为了避免不必要的交换,我们只在0左边有1的情况下进行交换。每次交换都会让0往左移动,这样可以在尽量少的交换次数内调整字符串。

具体实现

我们实现的策略是,从左到右遍历字符串中的每个字符,遇到0时尝试将它交换到前面,直到交换次数k用尽。每次遇到0时,判断它前面是否有1,如果有且k还有剩余,就交换这两个字符,直到不能再交换为止。

代码实现

def solution(n: int, k: int, s: str) -> str:
    s = list(s)  # 转换为列表以便进行交换
    for i in range(n):
        if s[i] == '0':
            j = i
            while j > 0 and k > 0 and s[j - 1] == '1':
                # 交换相邻字符
                s[j], s[j - 1] = s[j - 1], s[j]
                j -= 1
                k -= 1
    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 = list(s),由于字符串是不可变的,我们需要将字符串转换为列表,这样我们可以在列表中修改字符。
  2. 遍历字符串for i in range(n),我们遍历字符串中的每个字符。每当遇到一个0时,尝试将其交换到前面。
  3. 交换条件while j > 0 and k > 0 and s[j - 1] == '1',如果当前字符是0,且前面有1并且k还有剩余,我们就交换这两个字符。每交换一次,k减去1,直到k用完或没有更多的交换机会。
  4. 返回结果''.join(s),最后将字符列表重新连接成字符串并返回。

时间与空间复杂度

时间复杂度O(n),我们遍历一次字符串,检查每个字符,并进行最多k次交换操作。每次交换的时间复杂度为常数,因此总的时间复杂度为O(n)空间复杂度O(n),我们将字符串转换成列表并进行修改,因此空间复杂度是O(n)

总结和思考

这是我第二道困难题,虽然题目表面上看起来有一定的挑战性,但仔细分析后会发现,问题的关键在于利用贪心策略,逐步优化字符串的字典序。通过合理地控制交换次数,并结合每次交换的局部最优选择,我们可以在给定的约束条件下,轻松地得到字典序最小的结果。