📅  最后修改于: 2023-12-03 15:12:36.473000             🧑  作者: Mango
该题目是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:该字符出现的次数)和两个指针的处理,非常巧妙和高效地解决了该问题。