📜  门| GATE CS 2018 |第 56 题(1)

📅  最后修改于: 2023-12-03 15:12:36.473000             🧑  作者: Mango

GATE CS 2018 | 第56题

该题目是GATE计算机科学2018的第56题,题目描述如下:

给定一个字符串S,找到S中最短且包含所有字符的子串。

C++代码如下:

#include <bits/stdc++.h>
using namespace std;

int main()
{
    string S, tmp;
    getline(cin, S);
    const int INF = 0x3f3f3f3f;

    int cnt[256];
    memset(cnt, 0, sizeof(cnt));
    int dist_chars = 0;
    for (int i = 0; i < S.length(); i++)
    {
        cnt[S[i]]++;
        if (cnt[S[i]] == 1)
            dist_chars++;
    }

    int left = 0, right = 0;
    int ans_left = -1, ans_right = -1;
    int ans = INF;
    memset(cnt, 0, sizeof(cnt));
    int curr_dist_chars = 0;

    while (right < S.length())
    {
        if (cnt[S[right]] == 0)
            curr_dist_chars++;

        cnt[S[right]]++;

        while (curr_dist_chars == dist_chars && left <= right)
        {
            if (right - left + 1 < ans)
            {
                ans = right - left + 1;
                ans_left = left;
                ans_right = right;
            }

            cnt[S[left]]--;
            if (cnt[S[left]] == 0)
                curr_dist_chars--;

            left++;
        }

        right++;
    }

    if (ans_left == -1)
        cout << "No substring found" << endl;
    else
        cout << S.substr(ans_left, ans) << endl;

    return 0;
}

该程序处理字符串的效率比较高,解题思路是利用滑动窗口的方法,先统计字符串中共有多少种字符,再通过滑动窗口找出最短且包含所有字符的子串。

程序首先统计了字符串中出现的所有字符(包括重复的字符)的个数,在需要统计字符个数的时候使用了memset函数来将数组清零。

程序中定义了两个指针left和right,分别指向滑动窗口的左端点和右端点。开始时两个指针都指向0位置。

right从0开始往右滑动,将新的字符存入cnt数组(表示字符出现的个数),同时如果这个字符没有出现过,则将distinct_chars(不同字符出现频率)+1,表示新增加了一个不同的字符。

left指针在右移动的过程中删去cnt数组中对应的字符,同样也需要更新distinct_chars。

代码中还有一些比较巧妙的处理方法,例如最上面利用getline函数读取一行字符串的方法,最后利用substr函数找到最短的子串。

总的来说,该程序利用了滑动窗口的思想,用了array的字典(key:字符,value:该字符出现的次数)和两个指针的处理,非常巧妙和高效地解决了该问题。