最小替换子串长度| 豆包MarsCode AI刷题

113 阅读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. 计算目标频次:由于字符串长度是4的倍数,目标频次是字符串长度除以4。
  2. 统计当前频次:统计字符串中每个字符ASDF的当前频次。
  3. 计算差值:计算每个字符需要增加或减少的频次,使得每个字符的频次达到目标频次。
  4. 滑动窗口:使用滑动窗口技术来找到一个最小的子串,使得通过替换这个子串中的字符,可以满足所有字符的频次要求。
    n = len(input)
    target_freq = n // 4  # 目标频次
    
    # 统计当前频次
    current_freq = {'A': 0, 'S': 0, 'D': 0, 'F': 0}
    for char in input:
        current_freq[char] += 1
    
    # 计算每个字符需要增加或减少的频次
    needed_changes = {char: max(0, current_freq[char] - target_freq) for char in 'ASDF'}
    
    # 如果所有字符的频次已经相等,直接返回0
    if sum(needed_changes.values()) == 0:
        return 0
    
    # 使用滑动窗口找到最小的子串
    left = 0
    min_length = n  # 初始化为最大可能值
    window_count = {'A': 0, 'S': 0, 'D': 0, 'F': 0}
    
    for right in range(n):
        window_count[input[right]] += 1
        
        # 检查当前窗口是否满足所有字符的频次要求
        while all(window_count[char] >= needed_changes[char] for char in 'ASDF'):
            min_length = min(min_length, right - left + 1)
            window_count[input[left]] -= 1
            left += 1
    
    return min_length

if __name__ == "__main__":
    #  You can add more test cases here
    print(solution("ADDF") == 1)
    print(solution("ASAFASAFADDD") == 3)

关键步骤解释

  1. 统计当前频次:使用字典current_freq来记录每个字符的当前频次。
  2. 计算差值:使用字典needed_changes来记录每个字符需要增加或减少的频次。
  3. 滑动窗口:使用两个指针leftright来表示当前窗口的边界,window_count记录当前窗口内每个字符的频次。通过移动right指针扩展窗口,移动left指针缩小窗口,直到找到满足条件的最小子串。

心得体会

1. 问题分解与模块化

代码首先将问题分解为几个关键步骤:计算目标频次、统计当前频次、计算差值、以及使用滑动窗口找到最小子串。这种模块化的设计使得代码结构清晰,易于理解和维护。

2. 字典的使用

字典在代码中被广泛使用,用于统计字符的频次和记录需要的变化量。字典的键值对结构非常适合这种需要快速查找和更新的场景。

3. 滑动窗口技术

滑动窗口技术是解决这类问题的有效方法。通过维护一个窗口,可以在O(n)的时间复杂度内找到满足条件的最小子串。滑动窗口的核心在于动态调整窗口的边界,以确保窗口内的字符频次满足要求。

4. 边界条件的处理

代码中对边界条件进行了细致的处理。例如,当所有字符的频次已经相等时,直接返回0,避免了不必要的计算。这种对边界条件的处理可以提高代码的效率和鲁棒性。

5. 代码的可读性和可维护性

代码的注释和变量命名都很清晰,有助于理解代码的逻辑。良好的代码风格和注释习惯可以提高代码的可读性和可维护性。

6. 测试用例的重要性

代码末尾提供了测试用例,这有助于验证代码的正确性。通过添加更多的测试用例,可以覆盖更多的边界情况,确保代码的健壮性。

7. 时间复杂度分析

代码的时间复杂度为O(n),其中n是字符串的长度。滑动窗口的每次操作都是线性的,因此整体的时间复杂度是可接受的。

8. 空间复杂度分析

代码的空间复杂度为O(1),因为使用了固定大小的字典来存储频次信息,不随输入规模增大而增加。

标签:juejin.cn/tag/%E9%9D%…