C.字符串
题目链接-C.字符串
解题思路
- 如果字符串 s s s的长度大于字符串 t t t的长度,那么 s s s的任何排列都不可能是 t t t的子串,直接输出 0 0 0即可
- 因为要求 s s s的不同排列有多少种是 t t t的子串,将 s s s的不同排列全部求出来肯定会超时,我们可以直接计算 s s s中每个字母的个数,那么 t t t中如果有子串中各个字符个数与 s s s相同则说明是该子串是 s s s的一种排列
-
t
t
t中满足条件的子串可能会有排列相同的情况,这时我们就可以将每个满足条件的子串放入
set
容器中去重,最后输出set
中元素个数即可 - 在
i>=x-1
时,我们可以先判断当前位置的字母 t i t_i ti的数目是否与字符串 s s s相同,如果当前位置的字母都不满足条件那么就没有继续判断其他字母的必要,类似于一个剪枝操作 - 记得删除过期元素
t
i
−
t
t_{i-t}
ti−t(
b[t[i-x]-'a']--
),其实就是滑动窗口问题,维护一个长度为s.length()
的子串,类似于单调队列求解问题 - 具体操作见代码
附上代码
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
#define int long long
#define lowbit(x) (x &(-x))
#define endl '\n'
using namespace std;
const int INF=0x3f3f3f3f;
const int dir[4][2]={-1,0,1,0,0,-1,0,1};
const double PI=acos(-1.0);
const double e=exp(1.0);
const double eps=1e-10;
const int M=1e9+7;
const int N=2e5+10;
typedef long long ll;
typedef pair<int,int> PII;
typedef unsigned long long ull;
string s,t;
set<string> st;
int a[30],b[30];
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>s>>t;
int x=s.length();
int y=t.length();
if(x>y){
cout<<0<<endl;
return 0;
}
for(int i=0;i<x;i++)
a[s[i]-'a']++;
for(int i=0;i<y;i++){
b[t[i]-'a']++;
if(i>=x-1){
if(i!=x-1) b[t[i-x]-'a']--;
if(b[t[i]-'a']==a[t[i]-'a']){
bool ass=0;
for(char j='a';j<='z';j++){
if(b[j-'a']!=a[j-'a']){
ass=1;
break;
}
}
if(!ass)
st.insert(t.substr(i-x+1,x));
}
}
}
cout<<st.size()<<endl;
return 0;
}