资源限制
时间限制:1.0s 内存限制:512.0MB
问题描述
回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
交换的定义是:交换两个相邻的字符
例如mamad
第一次交换 ad : mamda
第二次交换 md : madma
第三次交换 ma : madam (回文!完美!)
输入格式
第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)
第二行是一个字符串,长度为N.只包含小写字母
输出格式
如果可能,输出最少的交换次数。
否则输出Impossible
样例输入
5
mamad
样例输出
3
——————————————————————————————————————————————————
大题思路就是,从头遍历每个字符,找到与它相同的最后一个字符 c,把 c 交换到末尾,然后 头++,末尾- -
参考原文
import java.util.Scanner;
public class Main {
static int n;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
sc.nextLine();
String str = sc.nextLine();
sc.close();
solve(str);
}
private static void solve(String str) {
int step = 0;
int flag = 0;//flag判断是否已经有一个单独的奇数个的字符了
char[] cs = str.toCharArray();
int tail = n - 1;//尾指针
for(int head = 0;head < tail;head++) {//0--n-2, 从前往后遍历字符
for(int k = tail;k >= head;k--) {//k指针从后往前寻找和cs[head]相同的字符
if(k == head) {//说明cs[head]是唯一的
if(n % 2 == 0 || flag == 1) {
System.out.println("Impossible");
return ;
}
//n是奇数
flag = 1;
//将cs[head]移动到正中间的步数,我们最后处理那个单独的字符
//比如 qaamm,我们只记录下q移动到中间的步数就不用管他了,不进行真正的交换
//因为现在交换到中间,也会被后面的操作破坏,徒增步数
//所以合理的理解是跳过单独字符q,记录完qaamm交换成qamma的步数后再结算q的步数,
//因为这样的结算只进行一次,且只是步数相加,没有真正的交换数组元素,不会破坏已经构建好的回文结构
//所以不用真的等到最后结算,啥时候发现q,啥时候结算
step += n / 2 - head;
}else if(cs[k] == cs[head]) {
for(int l = k;l < tail;l++) {//把cs[k]交换到cs[tail]处
swap(cs, l, l + 1);
step++;
}
tail--;//head与tail成了回文,继续处理内圈head++ 和 tail--
break;//k指针完成了cs[head]----cs[tail]的回文任务,无需继续循环
}
}
}
System.out.println(step);
}
private static void swap(char[] cs, int l, int i) {
char t = cs[l];
cs[l] = cs[i];
cs[i] = t;
}
}