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

38 阅读3分钟

最小替换子串长度

要解决这个问题,我们需要使得字符串中的字符A、S、D、F的频率相等,而实现这一目标时所需替换的最小字串长度就是我们要求的。

1 分析:

  1. 假设输入字符串的长度为 n,那么每个字符 A、S、D、F 应该各自出现 n / 4 次。
  2. 我们的目标是通过尽可能少的替换,使得所有字符都出现 n / 4 次。
  3. 如果某些字符的频率超过 n / 4,我们需要用其他字符来替换超出的部分。
  4. 我们需要找到一个最短的子串,使得替换这个子串中的字符后,整个字符串中 A、S、D、F 的频率变得相等。

2 解题思路:

  • 使用滑动窗口的方法来寻找满足条件的最小子串。
  • 首先计算字符串中 A、S、D、F 的初始频率。
  • 如果初始频率已经满足要求,则不需要替换,直接返回0。
  • 否则,使用滑动窗口去寻找一个最短的子串,使得替换这个子串可以让 A、S、D、F 的频率达到 n / 4。

3 核心思想:

解题的核心思想是滑动窗口,当窗口内所有字符的频率都不超过n/4时,我们尝试缩小窗口,并更新最小子串长度。

逻辑如下:

1、初始化频率统计:首先统计整个字符串中A、S、D、F的频率。

2、判断平衡:如果字符的频率已经符合n/4的要求,那么返回0(即不需要替换)。

3、使用滑动窗口寻找最短子串:

  • 左指针 left 和右指针 right 分别表示窗口的起始和结束位置。
  • 遍历字符串,当右指针 right 向右移动时,我们减少 right 位置字符的频率。
  • 当窗口内的字符频率都低于或等于 n/4 时,说明此窗口中的字符可以通过替换来达到平衡

例如字符串:

ASAFASAFADDD

(1)初始化频率统计:count[A]=5,count[S]=2,count[F]=2,count[D]=3,minLen初始化为n

(2)判断平衡:n/4是3,现在不满足平衡的条件

(3)使用滑动窗口寻找最短子串

  • left=0,right=0,count[A]=4,count[S]=2,count[F]=2,count[D]=3,频率不都小于等于3,right++
  • left=0,right=1,count[A]=4,count[S]=1,count[F]=2,count[D]=3,频率不都小于等于3,right++
  • left=0,right=2,count[A]=3,count[S]=1,count[F]=2,count[D]=3,频率都小于等于3,minLen=min(minLen,right-left+1),minLen=3,count[A]++,left++,频率不都小于等于3,right++
  • left=1,right=3,count[A]=4,count[S]=1,count[F]=1,count[D]=3,频率不都小于等于3,right++
  • left=1,right=4,count[A]=3,count[S]=1,count[F]=1,count[D]=3,频率都小于等于3,minLen=min(minLen,right-left+1),minLen=3,count[S]++,left++,频率都小于等于3,minLen=min(minLen,right-left+1),minLen=3,count[A]++,left++,频率不都小于等于3,right++
  • left=3,right=5,count[A]=4,count[S]=2,count[F]=1,count[D]=3,频率不都小于等于3,right++
  • 以此递推,最终得到最小的minLen=3

代码:

#include <iostream>
#include <string>
#include <unordered_map>
#include <algorithm>

int solution(std::string input) {
    int n = input.size();
    int target = n / 4;
    std::unordered_map<char, int> count;

    // 统计 A, S, D, F 的频率
    for (char c : input) {
        count[c]++;
    }

    // 检查是否已经符合要求
    if (count['A'] == target && count['S'] == target && count['D'] == target && count['F'] == target) {
        return 0;
    }

    // 滑动窗口寻找最小的子串
    int min_length = n;
    int left = 0;
    for (int right = 0; right < n; ++right) {
        count[input[right]]--;

        // 检查当前窗口是否满足要求
        while (count['A'] <= target && count['S'] <= target && count['D'] <= target && count['F'] <= target) {
            min_length = std::min(min_length, right - left + 1);
            count[input[left]]++;
            left++;
        }
    }

    return min_length;
}

int main() {
    //  You can add more test cases here
    std::cout << (solution("ADDF") == 1) << std::endl;
    std::cout << (solution("ASAFASAFADDD") == 3) << std::endl;
    return 0;
}