问题描述
回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
交换的定义是:交换两个相邻的字符
例如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) {
/*
由问题描述可以得知,有两种情况会输出“Impossible”,
一种是当字符串长度为奇数且出现两个及两个以上出现次数为奇数个的字符,
另一种是字符串长度为偶数但存在出现次数为奇数个的字符。
当字符串具备构成一个完美的回文串条件时,
我们可以从最左边的元素开始查找,然后从右向左查找能够和最左边元素匹配的字符,
若匹配成功则将该字符交换至字符串的最右边,然后将从右边查找的标记下标减一并从紧邻最左边的第二个字符开始再次查找,
依次类推直至两个索引标记相等。
*/
Scanner scanner = new Scanner(System.in);
int N = scanner.nextInt();// 输入字符串长度
char[] chars = scanner.next().toCharArray();// 输入字符串
int cnt = 0,odd = 0;// cnt最小交换次数,odd判断是否已经存在一个单独的奇数个数的字符了
int end = N - 1;
for (int i = 0; i < end; i++) {
for (int j = end; j >= i; j--) {
if (i == j){// 向左查找没有找到相同的字母
if (N % 2 == 0 || odd == 1){// 如果给定字符串是偶数且存在次数为奇数个的字符或者存在两个出现次数为奇数个的字符
System.out.println("Impossible");
return;// 结束
}
odd = 1;// 字符串长度为奇数,且找到了一个出现次数为奇数的字母,即索引为i的字母
cnt += N/2 - i;// 将奇次字符交换到中间位置的次数
}
// 从右如果找到重复的字母,
else if (chars[i] == chars[j]){
for (int k = j; k < end; k++ ) {
char temp = chars[k];
chars[k] = chars[k + 1];
chars[k + 1] = temp;
cnt ++;// 交换一次,cnt ++
}
end --;// 末尾索引左移
break;// 结束内层循环,继续外层,类似递归
}
}
}
System.out.println(cnt);
}
}