伴学笔记|豆包MarsCode AI刷题

46 阅读4分钟

问题描述

小F得到了一个特殊的字符串,这个字符串只包含字符ASDF,其长度总是4的倍数。他的任务是通过尽可能少的替换,使得ASDF这四个字符在字符串中出现的频次相等。求出实现这一条件的最小子串长度。

测试样例

样例1:

输入:input = "ADDF"
输出:1

样例2:

输入:input = "ASAFASAFADDD"
输出:3

样例3:

输入:input = "SSDDFFFFAAAS"
输出:1

样例4:

输入:input = "AAAASSSSDDDDFFFF"
输出:0

样例5:

输入:input = "AAAADDDDAAAASSSS"
输出:4

解题思路

  1. 字符串的长度特性

    • 字符串的长度 n 总是 4 的倍数。因为最终需要将每个字符的出现次数调整为相等,那么每个字符最终应该出现的次数是 n / 4
  2. 计算目标频次

    • 设目标频次 target = n / 4,即每个字符应该出现的次数。
  3. 统计字符频次

    • 我们可以统计字符串中每个字符的出现次数,并计算当前各个字符的差异(即当前频次与目标频次的差值)。如果某个字符的出现次数大于目标频次,则多出来的部分可以用于替换;如果某个字符的出现次数小于目标频次,则需要替换其他字符来增加该字符的频次。
  4. 使用滑动窗口(滑动区间)

    • 我们的目标是找出一个最小的子串,使得替换后,四个字符的频次能够相等。由于我们需要考虑替换操作的最小子串长度,可以使用滑动窗口来高效求解。
    • 滑动窗口的做法是从字符串的左侧开始遍历,同时调整窗口的大小,保持窗口内的字符频次尽量接近目标频次。当窗口内的字符频次接近目标频次时,我们尝试缩小窗口,最终得到最小的窗口长度。
  5. 具体步骤

  • 统计整个字符串的字符频次。
  • 计算每个字符的多余部分(即大于目标频次的部分)和缺失部分(即小于目标频次的部分)。
  • 使用滑动窗口(双指针)方法,尽可能将窗口内的字符频次调整为目标频次。

代码解释

  1. 初始化与统计频次

    • target = n // 4 表示每个字符应该出现的次数。
    • 使用 Counter(input) 来统计字符串中每个字符的出现次数。
  2. 滑动窗口

    • leftright 是滑动窗口的左右边界,right 逐步向右移动,每次扩展窗口。
    • window_count 用于统计当前窗口内各字符的频次。
  3. 窗口调整

    • 对每一个扩展后的窗口,我们检查其内的字符频次是否都不超过目标频次 target。如果是,说明当前窗口内的字符频次已经平衡,可以缩小窗口,移动 left 指针来尽量减小子串长度。
  4. 最小子串长度

    • 在每次调整窗口时,我们记录窗口的最小长度 min_length,即最小的替换操作所需子串长度。

测试样例分析

样例 1

输入:"ADDF"

  • 目标频次:每个字符的目标频次为 4 // 4 = 1
  • 当前频次:A: 1, D: 2, F: 1,需要替换一个 DAF
  • 最小替换子串长度是 1,因为只需要一个字符替换。

样例 2

输入:"ASAFASAFADDD"

  • 目标频次:每个字符的目标频次为 12 // 4 = 3
  • 当前频次:A: 4, S: 3, F: 3, D: 2,需要将一个 A 替换为 D,所以最小替换子串长度是 3。

样例 3

输入:"SSDDFFFFAAAS"

  • 目标频次:每个字符的目标频次为 12 // 4 = 3
  • 当前频次:S: 3, D: 3, F: 4, A: 2,需要替换一个 FA,最小替换子串长度是 1。

样例 4

输入:"AAAASSSSDDDDFFFF"

  • 目标频次:每个字符的目标频次为 16 // 4 = 4
  • 当前频次已经满足目标频次,所以无需替换,输出为 0。

样例 5

输入:"AAAADDDDAAAASSSS"

  • 目标频次:每个字符的目标频次为 16 // 4 = 4
  • 当前频次:A: 6, D: 3, S: 4,需要替换两个 A 和一个 D,最小替换子串长度为 4。

总结

  • 滑动窗口 是处理这类子串问题的高效方法,通过动态调整窗口大小来达到最小化替换的目标。
  • 时间复杂度:每个字符的频次最多更新一次,滑动窗口的左右指针遍历整个字符串,因此时间复杂度为 O(n),其中 n 是字符串的长度。
  • 空间复杂度O(1),只使用了固定数量的额外空间来存储窗口内的字符频次。