问题描述
回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
交换的定义是:交换两个相邻的字符
例如mamad
第一次交换 ad : mamda
第二次交换 md : madma
第三次交换 ma : madam (回文!完美!)
输入格式
第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)
第二行是一个字符串,长度为N.只包含小写字母
输出格式
如果可能,输出最少的交换次数。
否则输出Impossible
样例输入
5
mamad
样例输出
3
算法思想为:
* 先从左侧开始查找已经标记的奇数字母,
* 若遍历的字母i为标记字母,则以右侧相对应位置n-i-1为基准,在左侧找这个基准字母j,找到之后,移动(j-i)到标记字母i处
* 若字母i不为标记字母,则以左侧字母i为基准,找等于它的字母j,移动(n-i-1-j)字母i到对应的右侧位置
import java.io.*;
import java.util.Scanner;
public class Main {
public static void main(String args[]) throws IOException {
Scanner sc=new Scanner(System.in);
int n = Integer.parseInt(sc.nextLine());
String s = sc.nextLine();
char c[] = s.toCharArray();
char ch = '0';
int i, k = 0, j;
int b[] = new int[26]; // 记录'a'~'z'出现的次数
for (i = 0; i < n; i++)
for (i = 0; i < n; i++) {
j = c[i] - 'a';
b[j]++;
}
for (j = 0; j < 26; j++) {
if (b[j] % 2 != 0) {// b[j]是奇数
k++; //记录奇数数目
ch = (char) (j + 'a');//记录奇数的字母
}
}
if (k >= 2)//如果超过两次则不可能形成完美回文
System.out.println("Impossible");
else
System.out.println(changes(c, ch, n));
}
/**
* 算法思想为:
* 先从左侧开始查找已经标记的奇数字母,
* 若遍历的字母i为标记字母,则以右侧相对应位置n-i-1为基准,在左侧找这个基准字母j,找到之后,移动(j-i)到标记字母i处
* 若字母i不为标记字母,则以左侧字母i为基准,找等于它的字母j,移动(n-i-1-j)字母i到对应的右侧位置
* @param s
* @param x
* @param n
* @return
*/
public static int changes(char s[], char x, int n) {
int i, change = 0, j, k;
for (i = 0; i < n / 2; i++) {//先从左侧开始查找已经标记的奇数字母
if (s[i] == x) {//遍历的字母i为标记字母
for (j = i; j < n - i - 1; j++)//则以右侧相对应位置n-i-1为基准,在左侧找这个基准字母j
if (s[n - i - 1] == s[j])
break;
change += j - i;//移动(j-i)到标记字母i处
for (k = j; k > i; k--)
s[k] = s[k - 1];
s[i] = s[n - i - 1];
} else {//若字母i不为标记字母
for (j = n - i - 1; j >= i; j--)
if (s[i] == s[j])//则以左侧字母i为基准,找等于它的字母j
break;
change += n - i - 1 - j;//移动(n-i-1-j)字母i到对应的右侧位置
for (k = j; k < n - i - 1; k++)
s[k] = s[k + 1];
s[n - i - 1] = s[i];
}
}
return change;
}
}