问题描述
回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
交换的定义是:交换两个相邻的字符
例如mamad
第一次交换 ad : mamda
第二次交换 md : madma
第三次交换 ma : madam (回文!完美!)
输入格式
第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)
第二行是一个字符串,长度为N.只包含小写字母
输出格式
如果可能,输出最少的交换次数。
否则输出Impossible
样例输入
5
mamad
样例输出
3
算法思路
由问题描述可以得知,有两种情况会输出“Impossible”,一种是当字符串长度为奇数且出现两个及两个以上出现次数为奇数个的字符,另一种是字符串长度为偶数但存在出现次数为奇数个的字符。当字符串具备构成一个完美的回文串条件时,我们可以从最左边的元素开始查找,然后从右向左查找能够和最左边元素匹配的字符,若匹配成功则将该字符交换至字符串的最右边,然后将从右边查找的标记下标减一并从紧邻最左边的第二个字符开始再次查找,依次类推直至两个索引标记相等。
算法实现
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int num = input.nextInt();
String s = input.next();
int oldNum = 0;//判断是否已经存在一个单独的奇数个数的字符了
int cnt = 0;//总共交换次数
int end = num - 1;//字符串最后一个字符的下标
char[] chars = s.toCharArray();
for (int i = 0; i < end; i++) {
for (int j = end; j >= i; j--) {
if(i == j){//chars[i]未找到与之相等的字符
if(num % 2==0 || oldNum == 1){//字符串长度为偶数个且存在出现次数为奇数个的字符或者存在两个出现次数为奇数个的字符
System.out.println("Impossible");
return;
}
oldNum = 1;//字符串长度为奇数且找到一个字符出现的次数为奇数
cnt += num / 2 - i;//将奇次字符交换到中间位置的次数
}
if(chars[i]==chars[j]){//如果找到了,将chars[j]交换到最后
for (int k = j; k < end; k++) {
char t = chars[k];
chars[k] = chars[k + 1];
chars[k + 1] = t;
cnt++;
}
end--;//末尾递减
break;
}
}
}
System.out.println(cnt);
}
}