解题思路:
回文字符串有一个明显的特点即左右对称如:madam以‘d’为界限左右对称,很明显字符数为奇数且除了d外其他字母都成对存在,如果有两个d则为maddam,既然字符串呈轴对称那么就可以想到让对称轴左边不动,右边按照左边的顺序进行排列,排列时统计最少需要交换的次数。
注意!!题目中要求通过相邻两项的交换来时字符到达指定位置,因此不能跨越字符进行交换,跨越虽然也能使其达到效果,但记录出的次数不符合题目要求!!
现在来思考如何实现交换。可以从左边第一个字符开始如:mamda先用一个指针left指向他,再用一个指针right指向字符串最后一个元素。left先不动让right向左查找和left指向的字符相同的字符,如果找到了,就依次将其交换至最后一位,同时用count++记录交换的次数。之后让left指向下一个字符重复上述操作,显然这里使用双层for循环很方便外层代表left变化,里面一层代表right。由于没拍好一个字符所需要遍历的字符就少一个即right的起始位置就往前一个因此有需要tempz-1在每次排好一个后--来改变right起始位置。
如果遍历过程中发现该字符是单独的,即找到了单独的字符,就需要分情况:
1:字符串个数为奇数那么同时用一个变量来记录单独字符的个数,若大于一个则该字符串没法变成回文字符串,之后计算出该单独字符移到对称轴位置需要交换的次数加到count中即可。
2:字符串个数为偶数,只要出现单独的字符则一定无法构成回文字符串。
大概思路就是如此下面是具体代码。
#include<stdio.h>
void swap(char* p1, char* p2)//字符交换函数
{
char temp;
temp = *p1;
*p1 = *p2;
*p2 = temp;
}
int fcounts(char* str, int sz)
{
int count = 0,a=0;
int left, right, tmp = sz - 1;
for (left = 0; left <tmp; left++) //改变left指向的地方
{
for (right = tmp; right >= left; right--) //改变right指向的地方
{
if (left == right) //如果left=right说明这个字符是单身因为不是单身的会走下面else中的代码
{
if (sz % 2 == 0)//如果是偶数个
return -1;
else //如果是奇数个
{
a++;
count += sz / 2 - right;
break;
}
}
else {
if (str[left] == str[right])
{
for (int z = right; z <tmp; z++)
{
swap(str + z, str + z + 1);
count++;
}
tmp--;//改变right起始位置
break;
}
}
}if (a > 1)
return -1;
}
return count;
}
int main()
{
int n;
scanf("%d", &n);
getchar(); //scanf不会读取\n会导致下面的gets拿走\n所以要在这用getchar拿走\n导致其无法拿走本应拿走的字符串!!
char str[81] = { 0 };
gets(str);
int result = fcounts(str, n);
if (result == -1)
printf("Impossible");
else
printf("%d", result);
return 0;
}