G-eli和字符串
题目描述
eli拿到了一个仅由小写字母组成的字符串。
她想截取一段连续子串,这个子串包含至少
k
k
k
kkk
kkk 个相同的某个字母。
她想知道,子串的长度最小值是多少?
注:所谓连续子串,指字符串删除头部和尾部的部分字符(也可以不删除)剩下的字符串。例如:对于字符串“arcaea”而言,“arc”、“rcae”都是其子串。而“car”、“aa”则不是它的子串。
输入描述:
第一行输入两个正整数
n
n
n
nnn
nnn 和
k
k
k
kkk
kkk(
1
≤
k
≤
n
≤
2000001
≤
k
≤
n
≤
2000001
≤
k
≤
n
≤
200000
1≤k≤n≤2000001 \le k \le n \le 2000001≤k≤n≤200000
1≤k≤n≤2000001≤k≤n≤2000001≤k≤n≤200000)
输入仅有一行,为一个长度为
n
n
n
nnn
nnn 的、仅由小写字母组成的字符串。
输出描述:
如果无论怎么取都无法满足条件,输出
−
1
−
1
−
1
−1-1−1
−1−1−1 。
否则输出一个正整数,为满足条件的子串长度最小值。
示例1
5 2
abeba
3
说明:选择“beb”子串,长度为3,其中包含相同的两个’b’
思路如下
方法类似于“尺取法”,也可以认为是尺取法 或 双针法,其实大致思路都一样,只不过是实现的方法不一样,,,它们的主要思路是:
- 先找到一个符合题意的区间,在这一题中就是 含有 k 个相同字母的区间。
- 之后在 保证这个区间符合题意的基础上不断缩小区间范围,去找到更短的区间 的答案,当该区间在缩小完之后 不符和题意了,那么在扩大这个区间,使该区间在此符合题意,此时再次进行 2 这一步操作
题解一(尺取法?)
#include<iostream>
#include<map>
#include<algorithm>
using namespace std;
const int Len = 200005;
int barrel[Len];
char ar[Len];
int main()
{
//freopen("T.txt","r",stdin);
map<char , int> mp;
int n,k;
cin >> n >> k >> ar;
int l = -1, r = -1;
//尺取 找到一个合适的区间
for(int i = 0; i < n; i ++)
{
mp[ar[i]] ++;
if(mp[ar[i]] == k)
{
r = i;
break;
}
}
if(r == -1)
{
cout<< -1 << endl;
return 0;
}
//不断缩紧、扩大区间
int len = 1e9;
while(l < r && l < n - k && r < n)
{
while(mp[ar[r]] == k && l < r)
{
len = min(len , r - l);
l ++;
mp[ar[l]] --;
}
r ++;
if(r == n) break;
mp[ar[r]] ++;
}
if(len == 1e9)
cout<<-1<<endl;
else
cout<<len<<endl;
return 0;
}
题解如下(双针法? 前缀和?)
#include<iostream>
#include<string>
using namespace std;
const int Len = 2e5 + 5;
int dp[Len][26];
int main()
{
int n,k;
string s;
cin >> n >> k >> s;
dp[0][s[0] - 'a'] = 1;
for(int i = 1; i < n; i ++)
{
for(int j = 0; j < 26; j ++)
{
dp[i][j] = dp[i - 1][j];
}
dp[i][s[i] - 'a'] ++;
}
//先找到一个合适的区间
int min_len = 1e9;
for(int i = 0; i < 26; i ++)
{
int l = 0,r = 0;
if(dp[n - 1][i] < k) continue;
while(l < n && dp[l][i] == 0) l ++;
while(r < n && dp[r][i] < k) r ++;
min_len = min(min_len , r - l + 1);
//对区间不断 扩大缩小范围
for(l ++; l < n; l ++)
{
if(s[l - 1] - 'a' == i)
{
r ++;
while(r < n && s[r] - 'a' != i) r ++;
if(r == n) break;
}
min_len = min(min_len , r - l + 1);
}
}
if(min_len != 1e9)
cout << min_len << endl;
else
cout << -1 << endl;
return 0;
}