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

67 阅读4分钟

字典序最小的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'

算法设计

  • 分析题目过后首先要明确最重要的一点,让尽可能多的0到字符串的前段,才能达到最小的状态
  1. 初始化:将输入的字符串转换为字符数组,方便后续的操作。
  2. 执行操作:循环 k 次,每次从左至右遍历字符串,寻找第一个满足条件的相邻字符对(即左边是 1 右边是 0),并将它们交换。这样可以确保尽可能多的 0 移动到前面,从而减少字典序。
  3. 构建结果:完成所有操作后,重新组合字符数组形成字符串并返回。

复杂度

初始化

  • 时间复杂度:将字符串转换为 runes 切片的时间复杂度为 O(n)

交换操作

  • 外层循环:进行 k 次交换操作,时间复杂度为 O(k)
  • 内层循环:每次交换操作需要从左到右遍历字符串,时间复杂度为 O(n)

因此,交换操作的总时间复杂度为 O(k⋅n)。

总体时间复杂度

  • 初始化:O(n)
  • 交换操作:O(k⋅n) 总体时间复杂度为 O(k⋅n)。

空间复杂度分析

  • runes 切片:存储字符串的 runes,空间复杂度为 O(n)。

总体空间复杂度为 O(n)。

代码

package main

import (
	"fmt"
	"strings"
)

func solution(n int, k int, s string) string {
	ch := []rune(s)
	for i := 0; i < k; i++ {
		for j := 0; j < n-1; j++ {
			if ch[j] == '1' && ch[j+1] == '0' {
				temp := ch[j]
				ch[j] = ch[j+1]
				ch[j+1] = temp
				break
			}
		}
	}
	ss := strings.Builder{}
	for _, c := range ch {
		ss.WriteRune(c)
	}
	return ss.String()
}

测试

func main() {
	fmt.Println(solution(5, 2, "01010") == "00101")
	fmt.Println(solution(7, 3, "1101001") == "0110101")
	fmt.Println(solution(4, 1, "1001") == "0101")
}

优化

当前的算法在每次交换操作中都从头开始遍历字符串,这导致了较高的时间复杂度。可以通过以下方式进行优化:

  1. 记录 1 的位置:使用一个队列或双端队列来记录所有 1 的位置,每次交换时直接从队列中取出下一个 1 的位置进行交换。
  2. 减少不必要的遍历:通过记录 1 的位置,可以避免每次都从头开始遍历字符串。

优化后的代码

package main

import (
	"fmt"
	"strings"
)

// solution 解决字典序最小的01字符串问题
func solution(n int, k int, s string) string {
	runes := []rune(s)
	ones := make([]int, 0)

	// 记录所有 '1' 的位置
	for i := 0; i < n; i++ {
		if runes[i] == '1' {
			ones = append(ones, i)
		}
	}

	for i := 0; i < k && len(ones) > 0; i++ {
		pos := ones[0]
		if pos > 0 && runes[pos-1] == '0' {
			runes[pos-1], runes[pos] = runes[pos], runes[pos-1]
			ones = append(ones[:0], ones[1:]...) // 移除第一个 '1' 的位置
			ones = append(ones, pos-1)          // 添加新的 '1' 的位置
		} else {
			ones = append(ones[:0], ones[1:]...) // 移除第一个 '1' 的位置
		}
	}

	return string(runes)
}

func main() {
	fmt.Println(solution(5, 2, "01010")) // 00101
	fmt.Println(solution(7, 3, "1101001")) // 0110101
	fmt.Println(solution(4, 1, "1001")) // 0101
}

优化后的时间复杂度

  • 初始化:记录所有 1 的位置的时间复杂度为 O(n)。
  • 交换操作:每次交换操作的时间复杂度为 O(1),总共进行 k 次交换操作,时间复杂度为 O(k)。

总体时间复杂度为 O(n+k)。

优化后的空间复杂度

  • runes 切片:存储字符串的 runes,空间复杂度为 O(n)。
  • ones 切片:存储所有 1 的位置,空间复杂度为 O(n)。

总体空间复杂度为 O(n)。