问题描述
问题描述
回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
交换的定义是:交换两个相邻的字符
例如mamad
第一次交换 ad : mamda
第二次交换 md : madma
第三次交换 ma : madam (回文!完美!)输入格式
第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)
第二行是一个字符串,长度为N.只包含小写字母输出格式
如果可能,输出最少的交换次数。 否则输出Impossible
样例输入
5 mamad
样例输出
3
思路:
① 首先,我们确定一点,该字符串中出现奇数次的字符最多只能有一个,
如果出现一个以上,该字符串注定不是回文串,我们输出Impossible即可
② 现在的情况一定是能够够成回文串的情况
那现在面临的问题是,怎么实现最小交换次数?
我们考虑单个字符
我们从左侧开始遍历,当遍历第i个字符的时候,我们从右侧对称位置往左 侧找对称字符,找到之后进行减缓,一定是这个字符对称所走的最小次数
所有单个字符都做最小步数,那么总体就是走的最小步数
我们上面看到如果没有奇数字符的话,上面的方法是可以得到结果的。
那么如果有奇数字符呢?
如果有奇数字符的话,我们不处理奇数字符;从奇数字符的对称位置往左边处理,即处理不含奇数字符的子串,和上述的处理过程相同。
代码实现
#include<iostream>
using namespace std;
#include<string>
int Fun(string str,char ch)
{
int count=0;
int n=str.size();
for(int i=0;i<n/2;++i)
{
if(str[i]==ch)
{
//如果是奇数字符
//我们需要从右侧 匹配对应的字母,进行移动
int j=i;
for(j=i;j<n-1-i;j++)
{
if(str[j]==str[n-1-i])
{
break;
}
}
count += j - i;
for (int k = j; k > i; k--) {
str[k] = str[k - 1];
}
str[i] = str[n - i - 1] ;
}
else
{
//不是奇数字母
//可以按照正常处理顺序,按照左侧的字母去右侧寻找对称的字母
int j=n-1-i;
for(j=n-1-i;j>=i;--j) //在i的位置必定能够找到
{
if(str[i]==str[j])
{
break;
}
}
count+=n-1-i-j;
for(int k=j;k<n-1-i;++k)
{
str[k]=str[k+1];
}
str[n-1-i]=str[i];
}
}
return count;
}
int main()
{
int N;
string str;
while(cin>>N>>str)
{
//一个数组,用来统计字符串中每个字母的个数
int count[26]={0};
for(int i=0;i<str.size();++i)
{
count[str[i]-'a']++;
}
int oddcount=0;
char oddch=0;
for(int i=0;i<26;++i)
{
if(count[i]%2!=0)
{
oddcount++;
oddch=i+'a';
}
}
//如果奇数的字母出现次数大于1,必定不能形成回文串
if(oddcount>1)
{
cout<<"Impossible"<<endl;
}
else
{
cout<<Fun(str,oddch)<<endl;
}
}
return 0;
}
觉得不错,来个赞呗