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

120 阅读6分钟

问题描述

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

测试样例:

示例一:

输入:input = "ADDF"

输出:1

示例二:

输入:input = "ASAFASAFADDD"

输出:3

示例三:

输入:input = "SSDDFFFFAAAS"

输出:1

示例四:

输入:input = "AAAASSSSDDDDFFFF"

输出:0

示例五:

输入:input = "AAAADDDDAAAASSSS"

输出:4

解题思路

  1. 理解问题:这个问题要求我们通过最少的替换操作,使得字符串中的字符'A'、'S'、'D'、'F'出现的次数相等,且这个次数是字符串长度除以4的结果。

  2. 初始化:首先,我们计算出每个字符应该出现的目标次数(target_freq),然后初始化一个字典(char_freq)来记录每个字符在字符串中的出现次数。

  3. 统计字符频率:遍历字符串,统计每个字符的出现次数。

  4. 检查初始状态:如果初始状态下,每个字符的出现次数已经等于目标次数,那么不需要任何替换,返回0。

  5. 滑动窗口:使用滑动窗口的方法来找到需要替换的最小子串长度。滑动窗口是一种在字符串问题中常用的技术,用于在不改变字符串其他部分的情况下,检查字符串的某个连续子串。

  6. 更新窗口:在滑动窗口的过程中,我们不断尝试缩小窗口,直到窗口内所有字符的出现次数都不大于目标次数。

  7. 记录最小长度:在滑动窗口的过程中,记录并更新需要替换的最小子串长度。

  8. 返回结果:最后,返回找到的最小长度。如果没有找到合适的子串长度,则返回0。

核心代码

def solution(input_str):
    # 计算每个字符的目标出现频率,因为字符串长度是4的倍数,所以是长度除以4
    target_freq = len(input_str) // 4
    # 初始化字符频率字典,'A'、'S'、'D'、'F'初始频率都为0
    char_freq = {"A": 0, "S": 0, "D": 0, "F": 0}

    # 遍历输入字符串,统计每个字符的出现频率
    for char in input_str:
        char_freq[char] += 1

    # 如果所有字符的出现频率已经等于目标频率,则不需要替换,直接返回0
    if all(char_freq[char] == target_freq for char in "ASDF"):
        return 0

    # 使用滑动窗口方法找到最小替换子串长度
    min_length = float('inf')  # 初始化最小长度为无穷大
    start = 0  # 滑动窗口的左边界
    for end in range(len(input_str)):  # 滑动窗口的右边界
        char_freq[input_str[end]] -= 1  # 将当前字符的频率减1

        # 如果窗口内所有字符的频率都不大于目标频率,则尝试缩小窗口
        while all(char_freq[char] <= target_freq for char in "ASDF"):
            min_length = min(min_length, end - start + 1)  # 更新最小长度
            char_freq[input_str[start]] += 1  # 将窗口左边界的字符频率加1
            start += 1  # 移动窗口左边界
            # 如果窗口左边界超过了右边界,跳出循环
            if start > end:
                break

    # 如果没有找到合适的子串长度,则返回0;否则返回找到的最小长度
    return min_length if min_length != float('inf') else 0


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

代码分析

  • target_freq = len(input_str) // 4:计算每个字符应该出现的目标次数。

  • char_freq = {"A": 0, "S": 0, "D": 0, "F": 0}:初始化字符频率字典。

  • for char in input_str:遍历字符串,统计每个字符的出现次数。

  • if all(char_freq[char] == target_freq for char in "ASDF"):检查初始状态下是否已经满足条件。

  • min_length = float('inf'):初始化最小长度为无穷大。

  • for end in range(len(input_str)):滑动窗口的右边界。

  • while all(char_freq[char] <= target_freq for char in "ASDF"):尝试缩小窗口。

  • min_length = min(min_length, end - start + 1):更新最小长度。

  • return min_length if min_length != float('inf') else 0:返回找到的最小长度或0。

核心知识

  1. 滑动窗口技术

    • 滑动窗口是一种在数组或字符串中维持一个窗口范围,并在满足一定条件下滑动窗口的起始或结束边界的算法策略。
    • 在本题中,滑动窗口用于在字符串中寻找一个子串,使得子串中的字符'A'、'S'、'D'、'F'出现次数相等。
  2. 字符频率统计

    • 字符频率统计是通过哈希表(字典)来记录每个字符在字符串中出现的次数。
    • 在本题中,使用字典char_freq来统计字符'A'、'S'、'D'、'F'的出现次数。
  3. 算法复杂度分析

    • 滑动窗口算法的时间复杂度通常为O(n),其中n是字符串的长度,因为每个元素最多被访问两次(一次由左到右,一次由右到左)。
  4. 贪心算法思想

    • 在尝试缩小窗口时,采取贪心策略,尽可能地缩小窗口以满足所有字符出现次数相等的条件。
  5. 字符串操作

    • 字符串是不可变的,因此在滑动窗口中,通过字符频率的更新来模拟窗口的滑动,而不是实际地在字符串上进行操作。
  6. 代码实现细节

    • 在代码实现中,注意使用min_length = float('inf')来初始化最小长度,确保任何实际的窗口长度都会小于这个初始值。
    • 使用if min_length != float('inf') else 0来处理没有找到合适子串长度的情况,确保返回0。

总结

这个问题的解决方案涉及到滑动窗口技术,以及字符频率的统计和条件判断。通过不断调整滑动窗口,我们可以找到需要替换的最小子串长度,以使得字符串中的'A'、'S'、'D'、'F'出现次数相等。这种方法既高效又直观,能够解决这类字符平衡问题。

使用豆包marscode AI的优势

  1. 代码审查与质量分析:对代码进行深入分析,识别潜在的安全漏洞和性能问题,提供代码质量报告,帮助开发者改进代码。

  2. 学习与培训:为初学者提供编程指导和最佳实践,通过互动式学习,帮助开发者提高编程技能。

  3. 集成与兼容性:与主流IDE(如Visual Studio Code, IntelliJ IDEA等)无缝集成,支持多种编程语言,如Python、Java、C++、JavaScript等。

  4. 个性化与适应性:根据用户偏好和编程习惯调整建议,通过不断学习用户的编码风格和习惯,提供更加个性化的支持。