问题描述
回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
交换的定义是:交换两个相邻的字符
例如mamad
第一次交换 ad : mamda
第二次交换 md : madma
第三次交换 ma : madam (回文!完美!)
交换的定义是:交换两个相邻的字符
例如mamad
第一次交换 ad : mamda
第二次交换 md : madma
第三次交换 ma : madam (回文!完美!)
输入格式
第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)
第二行是一个字符串,长度为N.只包含小写字母
第二行是一个字符串,长度为N.只包含小写字母
输出格式
如果可能,输出最少的交换次数。
否则输出Impossible
否则输出Impossible
样例输入
5
mamad
mamad
样例输出
3
贪心算法
思路:
先判断出现字母的个数为奇数的数量_count,若_count>1,就是impossible;如果_count为零,就是所有的都能配对成功,左边开始固定一个字母,就从右边对称位置开始往左边搜,第一个遇到一样的字母的就向右移到对应的位置。一直如此重复就解出来了;
单是_count=1时,寻找时会遇到找不到的情况,应为这个字母就是放在最中间,这个时候就要从右边开始固定,开始从左边开始位置向右边找,这样的话中间的那一个最后自己就到最中间去了;
接下来设定一种理想情况,就是不会被破坏的情况,就是最后回文中靠近两边的字母一定是更早到达对应的位置,因为如果是中间的元素更早到达平衡位置,你再调外侧的元素内侧一定会被打乱,所以假设一种理想情况,即不会被打乱的情况,那么假设此时移动的次数为理想距离;如果移动配对两侧的元素,他就是理想距离,但是配对两侧的元素的时候由于移动会使一些字母偏离理想距离,又会使一些字母更靠近理想距离,为什么呢,应为这样的操作会使字母往中间靠拢,有元素大于理想距离,就一定有元素小于理想距离,所以移动的总次数一定不会超过理想距离,所以这样的策略一定是对的。
/**
*
*/
package 基础练习;
import java.awt.Checkbox;
import java.util.Scanner;
/**
* @author Administrator 问题描述
* 回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,
* 请你计算最少的交换次数使得该串变成一个完美的回文串。 交换的定义是:交换两个相邻的字符 例如mamad 第一次交换 ad : mamda
* 第二次交换 md : madma 第三次交换 ma : madam (回文!完美!) 输入格式
* 第一行是一个整数N,表示接下来的字符串的长度(N <= 8000) 第二行是一个字符串,长度为N.只包含小写字母 输出格式
* 如果可能,输出最少的交换次数。 否则输出Impossible 样例输入 5 mamad 样例输出 3
*/
public class 完美的代价 {
/**
* @param args
*/
private static int change = 0; // 改变的次数
private static int old = 0; // 记录出现奇数次字符
private static char charold = 0;// 记录奇数字符
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
int N = Integer.parseInt(sc.nextLine());
String s = sc.nextLine();
char str[] = s.toCharArray();
Boolean flag = check(str); // 是否可以组成回文
if (!flag) {
System.out.println("Impossible");
} else {
for (int i = 0; i < N / 2; i++) {
if (str[i] != charold) {// 从右开始找对称
int j = 0;
for (j = N - 1 - i; j > i; j--) {
if (str[i] == str[j])// 找到
break;
}
change += N - 1 - i - j; // 移动次数
for (int j2 = j; j2 < N - 1; j2++) {
str[j2] = str[j2 + 1];
}
str[N - 1 - i] = str[i];// 对称点
}
// 从左边开始
else {
int j = 0;
for (j = i; j < N - 1 - i; j++) {
if (str[j] == str[N - 1 - i])
break;// 找到
}
change += j - i;// 移动次数
for (int j2 = j; j2 < i; j2--) {
str[j2] = str[j2 - 1];
}
str[i] = str[N - 1 - i]; // 对称点
}
}
System.out.println(change);
}
}
private static boolean check(char[] str) {
int arr[] = new int[26];
for (int i = 0; i < str.length; i++) {
arr[str[i] - 'a']++;
}
for (int i = 0; i < 26; i++) {
if (arr[i] % 2 == 1) {
old++;
charold = (char) (i + 'a');
}
}
if (old > 1)
return false;
return true;
}
}
提交到蓝桥杯系统只得了60分。 有四个没有ac不知道什么原因。还在研究中。。。。