codeforces1354B. Ternary String

题目如下
You are given a string 𝑠 such that each its character is either 1, 2, or 3. You have to choose the shortest contiguous substring of 𝑠 such that it contains each of these three characters at least once.

A contiguous substring of string 𝑠 is a string that can be obtained from 𝑠 by removing some (possibly zero) characters from the beginning of 𝑠 and some (possibly zero) characters from the end of 𝑠.

Input
The first line contains one integer 𝑡 (1≤𝑡≤20000) — the number of test cases.

Each test case consists of one line containing the string 𝑠 (1≤|𝑠|≤200000). It is guaranteed that each character of 𝑠 is either 1, 2, or 3.

The sum of lengths of all strings in all test cases does not exceed 200000.

Output
For each test case, print one integer — the length of the shortest contiguous substring of 𝑠 containing all three types of characters at least once. If there is no such substring, print 0 instead.

题目大意
给我们一个又数字‘1’,‘2’和‘3’随机排序构成的串,要求找出其中最短的子串且这三个数字均要存在

解题思路
在串里找目标,我们可以通过滑动窗口算法来实现
滑动窗口算法呢,分为左右两个边界,都从字符串的最左边开始,先从开始的地方向右扩展右边界,左右边界中间夹着的即为窗口,一般窗口里最终包含我们需要的内容,满足一定条件,就收缩左边,这里我们需要满足子串里三个数字均出现,直到收缩完成取到最小的符合要求的子串

点击查看代码
for(int right = 0; right < n; right++){
            cnt[s[right]]++; //扩展右边界
            while(cnt['1'] && cnt['2'] && cnt['3']){ //满足条件
                if(right - left + 1 < res){
                    res = right - left + 1; //每次窗口合法时,更新最大窗口长度

                }
                cnt[s[left]]--; //伴随收缩减少各数字的数量
                left++; //收缩左边界
            }
        }
这时,我们计算子串长度并输出

注意,在本题中可能出现runtime error 分配太大导致运行崩溃,所以建议把数组定义放在全局,自动清零,避免溢出;

完整代码

点击查看代码
#include <iostream>
#include <stdio.h>
#include <map>
#include <string.h>
using namespace std;

char s[200005]; //避免溢出

int main() {
    int t;
    scanf("%d", &t);
    while(t--){
        scanf("%s",s);
        int n = strlen(s);
        map<char, int> cnt; //统计子串中1,2,3的数量
        int left = 0;
        int res = n + 1;
        for(int right = 0; right < n; right++){
            cnt[s[right]]++; //扩展右边界
            while(cnt['1'] && cnt['2'] && cnt['3']){ //满足条件
                if(right - left + 1 < res){
                    res = right - left + 1; //每次窗口合法时,更新最大窗口长度

                }
                cnt[s[left]]--; //收缩左边界
                left++;
            }
        }
        if(res <= n){
            printf("%d\n",res);
        }else{
            printf("0\n");
        }
        }
    return 0;
}
posted @ 2025-07-01 21:05  sirro1uta  阅读(11)  评论(0)    收藏  举报