代码练习-字典序最小的01字符串 | 伴学笔记

54 阅读4分钟

问题描述

小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'

解题思路

问题理解

你需要通过最多 k 次相邻字符交换操作,使得字符串 s 的字典序最小。字典序最小意味着字符串中的字符应该尽可能地按照从小到大的顺序排列。

数据结构选择

由于我们需要频繁地进行字符交换操作,使用列表来存储字符串的字符会更加方便。列表支持高效的元素交换操作。

算法步骤

  1. 遍历字符串:从字符串的第一个字符开始,逐步向后遍历。
  2. 寻找最小字符:对于当前位置 i,在 i 之后的最多 k 个字符范围内寻找最小的字符。
  3. 交换字符:如果找到了比当前字符更小的字符,并且可以通过不超过 k 次交换将其移动到当前位置,则进行交换。
  4. 更新操作次数:每次交换后,减少 k 的值,表示已经使用了一次操作。
  5. 继续遍历:继续遍历字符串的下一个字符,直到遍历完整个字符串或 k 次操作用完。

具体步骤

  1. 初始化:将字符串转换为列表,便于进行交换操作。
  2. 遍历字符串:使用一个循环遍历字符串的每个字符。
  3. 寻找最小字符:在当前字符后面最多 k 个字符范围内寻找最小的字符。
  4. 计算交换次数:计算将最小字符移动到当前位置所需的交换次数。
  5. 进行交换:如果可以交换,则进行交换,并减少 k 的值。
  6. 返回结果:将列表转换回字符串并返回。

示例

以样例 n = 5, k = 2, s = "01010" 为例:

  • 初始字符串:01010
  • 第一次遍历:当前字符是 0,不需要交换。
  • 第二次遍历:当前字符是 1,后面有两个字符 0 和 1,找到最小的字符 0,可以交换到当前位置。
  • 第三次遍历:当前字符是 0,不需要交换。
  • 第四次遍历:当前字符是 1,后面有一个字符 0,找到最小的字符 0,可以交换到当前位置。
  • 最终结果:00101

完整代码

def solution(n: int, k: int, s: str) -> str:
    s_list = list(s)
    
    for i in range(n):
        min_index = i
        for j in range(i + 1, min(i + k + 1, n)):
            if s_list[j] < s_list[min_index]:
                min_index = j
        
        swaps = min_index - i
        
        while swaps > 0 and k >= swaps:
            s_list[min_index], s_list[min_index - 1] = s_list[min_index - 1], s_list[min_index]
            min_index -= 1
            swaps -= 1
            k -= 1
    
    return ''.join(s_list)

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

学习总结

这个问题教会了我们如何在受限的操作次数内优化字符串的字典序。我们学会了使用滑动窗口和贪心策略来寻找最优解,并通过具体实现来验证我们的策略。这个过程不仅提高了我们的编程能力,还让我们对字符串处理和优化问题有了更深入的理解。在未来的学习和工作中,我们可以将这种方法应用到类似的问题上,以寻找高效且优雅的解决方案。