问题描述 回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
交换的定义是:交换两个相邻的字符
例如mamad
第一次交换 ad : mamda
第二次交换 md : madma
第三次交换 ma : madam (回文!完美!)
输入格式
第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)
第二行是一个字符串,长度为N.只包含小写字母输出格式 如果可能,输出最少的交换次数。否则输出Impossible
样例输入
5
mamad
样例输出
3
整体代码:
#include<stdio.h>
int main()
{
char a[8000];
char c;
int i, j, n,t1=0;
int t = 0,k,sum=0;
int count[26] = { 0 };
scanf_s("%d", &n);
getchar();//缓冲接收到的\n
gets_s(a);
//确定各个字符的数量
for (i = 0; i < n; i++)
count[a[i] - 'a']++;
for (i = 0; i < 26; i++)
{
if (count[i] % 2 != 0)
t++;
}
j = n - 1;
//如果奇数个字母且有超过一个字母是奇数个则不可能
if (t > 1 && n % 2 != 0)
{
printf("Impossible");
return 0;
}
//如果偶数个字母且有字母数量为奇数也不可能
else if (t > 0 && n % 2 == 0)
{
printf("Impossible");
return 0;
}
else
{
// 贪心算法 重点
//从左到右遍历
for (i = 0; i < (n - 1)/2; i++)
{
//从右向做遍历
for (k = j; k > i; k--)
{
if (a[k] == a[i])
break;
}
//如果该字母为奇数个则跳过该字母等全部完成后再加上
if (k == i)
{
t1 = (n - 1) / 2 - k;
}
//找到对应字母和对应位置并记录交换次数
else
{
for (; k != j; k++)
{
c = a[k];
a[k] = a[k + 1];
a[k + 1] = c;
sum++;
//puts(a);
}
j--;
}
}
}
printf("%d", sum+t1);
return 0;
}
之中最难理解为
- 贪心算法
for (i = 0; i < (n - 1)/2; i++)
{
for (k = j; k > i; k--)
{
if (a[k] == a[i])
break;
}
if (k == i)
{
t1 = (n - 1) / 2 - k;
}
else
{
for (; k != j; k++)
{
c = a[k];
a[k] = a[k + 1];
a[k + 1] = c;
sum++;
//puts(a);
}
j--;
}
}
- 字母为中心字符是的计算
跳过这个字符的交换跳到下一个字符但对应位置仍是上一个
比如说是第三个为中心字符而第三个位置对应位置为第七个位置那么跳过这个字符进行下一个字符的对应
即第四个位置与第七个位置对应如图
之后再将第三个位置到第五个位置交换
//字母为中心字符时
if (k == i)
{
t1 = (n - 1) / 2 - k;
}