import java.util.*;
import java.util.Date;
import java.math.BigInteger;
/**
* Created with IntelliJ IDEA.
* Description:
* User: 简天成
* Date: 2022-01-11
* Time: 15:08
*/
public class Main {
/**
* //分析:
* //1.Impossible
* //奇数个字符出现的次数为1或0时才能实现回文,如果出现奇数的次数>=2,不能实现回文
* //如madam只出现了一个奇数个字符d可以实现回文,如madfam,出现了两个奇数个字符d和f,不能实现回文
* /*要判定能否出现回文,就需要统计每个字符出现的次数,这里我们用长度为26的数组来记录,
* * 因为a-z正好是26个字母。由于题目规定是小写字母,而a的ASCII码值为97,如果当前字符为a
* * 那么97-97为0,我们就把它放到数组下标为0的位置并将此位置记录为1,如果后面,再出现a,那么
* * 数组下标为0的位置+1。b、c……z也是如此,这样我们就实现了字符的计数。
* //如果可行,那么我们就要实现回文交换
* * //mamad;可以使用循环交换,也可以使用递归交换,这里我们选用递归交换
* * //2.查找最后一个字符出现的位置
* * //3.将一个字符交换到指定的位置
* * //4.奇数个字符的处理
* * //如dmama就需要先将d和m交换成mdmama再查找最后一个m出现的位置然后交换。
*/
private static int N;
private static char[] arr;
private static int count;//记录交换次数
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
arr = sc.next().toCharArray();//toCharArray:将字符串转换为字符数组
sc.close();
int[] numArr = new int[26];//用于记录每个字符出现的次数
int flag = 0;//对出现次数为奇数的字符进行计数
for (int i = 0; i < arr.length; i++) {
numArr[arr[i] - 'a']++;//这里注意:arr[i]里面放的是输入的字符,那么arr[i]-'a',该字符处于26字母的第几位,
//arr[i]-'a'也就是字母几,假如是c,c是第三位,arr[i]-'a'=3,说明numArr[3]++,也就是说明c字符出现过一次
//一共循环26次,记录26字符出现的次数,然后再去用判断次数%2==1,看看是否出现奇数的字符的个数
//统计只出现奇数次的字母的个数
}
//统计出现次数为奇数的字符的个数
for (int i = 0; i < 26; i++) {
if (numArr[i] % 2 == 1)
++flag;
}
//如果出现次数为奇数的字符的个数多于1个,则不能构成回文串
if (flag > 1)
System.out.println("Impossible");
else {//否则,我们去进行查找,但是循环只需要循环一半即可,因为你把前面的一半进行交换完了,后面的都对称了。
for (int i = 0; i < N / 2; i++) {
swap(LastIndex(i), N - i - 1);
}
System.out.println(count);
}
}
//交换,start:表示要交换的开始的位置;end:表示交换的结束的位置
private static void swap(int start, int end) {
if (start == end || arr[start] == arr[end]) {
return;//此时不需要交换
}
char temp = arr[start];
arr[start] = arr[start + 1];
arr[start + 1] = temp;
count++;
swap(start + 1, end);
}
//查找最后一次出现的位置
private static int LastIndex(int cur) {
/*mamadm,比如说对于第二个字母a,我们查找的时候就应该从倒数第二个位置开始
//cur=1,N=6;那么我们就应该从倒数第二个位置即下标为4开始倒着查找,4=N-cur-1;
从后倒着查找到下标为cur时就应该放弃*/
for (int i = N - cur - 1; i > cur; i--) {
if (arr[cur] == arr[i])
return i;
}
//如果从后倒着查找到下标为cur时还未找到相同的字符,那么就说明此字符为奇数个,而且这个奇数字符在第一位
//为什么要去交换呢???,把它交换到第二位呢?,因为我们在上面进行一半循环开始的时候,从i=0开始,我们直接从第一个i=0开始进行
//交换,自然你需要保证你的第一位是个成对字符,不能为奇数字符
//对于出现次数为奇数的字符串,就要先交换,再查找
swap(cur, cur + 1);
return LastIndex(cur);//交换过后重新查找一次
}
}
完美的代价:贪心算法(递归)
最新推荐文章于 2024-04-29 13:19:49 发布