题目描述:
给定一个字符串,要求删除一个种字母,使字符串成为回文串,并使删除的字符数量最小。
example: abcaacab 2
删除字符'b', acaaca 为回文串,所以最小数量 2.
思路分析:既然要删除一种字符,那么应该先找到这个要删除的字符,这里用双指针向中间遍历,当str[l]!=str[r],这时要么删除str[l] ,要么str[r](记作ch1 ch2)。那么接下来拿这两个字符(ch1 ch2)来试,当遇到str[l]!=str[r],判断这两个字符之一,是不是ch1 ,如果是,则跳过,cnt++,最后判断l 是否大于r,即能否删除ch1,使之变成回文串。继续同样方法判断ch2。最后比较答案。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e9+7;
void solve()
{
int n;
string str;
cin>>n>>str;
char ch1,ch2;
int cnt1=0;
int flag1=1,l=0,r=n-1;
while(l<=r)
{
if(str[l]!=str[r])
{
ch1=str[l];
ch2=str[r];
flag1=0;
break;
}
l++;
r--;
}
if(flag1==1)
{
cout<<0<<endl;
return ;
}
flag1=0;
l=0,r=n-1;
while(l<=r)
{
if(str[l]!=str[r])
{
if(str[l]!=ch1&&str[r]!=ch1) //删除ch1 无法得到回文,break并标记
{
flag1=1;
break;
}
if(str[l]==ch1) //str[l]是要删除的字符,直接跳过
{
cnt1++;
l++;
}
if(str[r]==ch1) //str[r]是要删除的字符,直接跳过
{
cnt1++;
r--;
}
}
else
{
l++;
r--;
}
}
int flag2=0;
int cnt2=0;
l=0,r=n-1;
while(l<=r)
{
if(str[l]!=str[r])
{
if(str[l]!=ch2&&str[r]!=ch2)
{
flag2=1;
break;
}
if(str[l]==ch2)
{
cnt2++;
l++;
}
if(str[r]==ch2)
{
cnt2++;
r--;
}
}
else
{
l++;r--;
}
}
if(flag1==0&&flag2==0) cout<<min(cnt1,cnt2)<<endl;
else if(flag1&&flag2) cout<<-1<<endl;
else if(flag1==0&&flag2) cout<<cnt1<<endl;
else if(flag1&&flag2==0) cout<<cnt2<<endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t=1;
cin>>t;
while(t--)
solve();
return 0;
}
当我以为自己的解法很好时,又看到另一种更妙的解法 。。。
直接枚举26个字母表示删除该字母是否可行,如果可行直接得到答案并比较。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=1e9+7;
void solve()
{
int n;
string s;
cin>>n>>s;
int res=0x3f3f3f3f;
int l=0,r=n-1,ans;
for(int i=0;i<26;i++)
{
l=0;
r=n-1;
ans=0;
while(l<=r){
if(s[l]==s[r])
{
l++;
r--;
}
else if(s[l]==i+'a')
{
l++;
ans++;
}
else if(s[r]==i+'a')
{
r--;
ans++;
}
else
{
break;
}
}
if(l>r)
{
res=min(res,ans);
}
}
if(res==0x3f3f3f3f) cout<<-1<<endl;
else cout<<res<<endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t=1;
cin>>t;
while(t--)
solve();
return 0;
}