目录
回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
交换的定义是:交换两个相邻的字符
例如mamad
第一次交换 ad : mamda
第二次交换 md : madma
第三次交换 ma : madam (回文!完美!)
第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)
第二行是一个字符串,长度为N.只包含小写字母
如果可能,输出最少的交换次数。
否则输出Impossible
5
mamad
3
? ? ? ? 这个题目文档是将字符串变成回文子串的最少交换次数,这是一个贪心问题,我们需要思考,怎么样才能保证他得到的交换次数是最小的,那么就是不能有浪费的交换次数。
? ? ? ? 我们思考,在判断一个字符串是否是回文子串时,我们常用的方法就是,定义两个指针left,right,初始化指针指向子串的头和尾节点,判断指针指向的字符是否相同,然后就能判断该字串是否是回文子串。
? ? ? ? 那么在这里我们肯定也是要找不符合的节点位置,那么在找到不符合的节点left和right后,我们还需要使用distance_left和distance_right方法来寻找从左边找和right相等的字符位置,以及从右边找和left相等的字符的位置,也就是和left节点相同的字符的位置和与right节点相同的字符的位置,然后要求是交换次数最少的,那么就用需要最小交换次数的字符,这样在变换之后两边的字符是符合最终要求的,只有中间的是存在不符合要求的,但永远会比两边的距离要小,这样交换次数也会越来越小,得到的结果也将会是最小的结果。
? ? ? ? 那么在思考,在进行这一步变换的最终结果中,实际上是可以看成将符合条件的字符移到了需要变换的left或者right的位置,就可以使用动态数组快速的变换过来,那么在这个变化过程中交换的次数实践上就是初始点的位置到目标点的距离,在进行累加即可得到最终的结果。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n = input.nextInt();
input.nextLine();
String s = input.nextLine();
ArrayList<Character> lst = new ArrayList<>();
for (char c:s.toCharArray()){
lst.add(c);
}
int left = 0,right = n-1;
int counts = 0;
boolean flag2 = true;
while (left < right){
if (lst.get(left) != lst.get(right)){
int l = distance_left(left,lst,right),r = distance_right(left,lst,right);
if (l == 10000 && r == -100) {
System.out.println("Impossible");
flag2 = false;
break;
};
if (l - left <= right - r){
char a = lst.remove(l);
lst.add(left,a);
counts += l-left;
}
else {
boolean flag = false;
if (right != n-1) flag= true;
char a = lst.remove(r);
if (flag)lst.add(right,a);
else lst.add(a);
counts += right - r;
}
}
left += 1;
right -= 1;
}
if (flag2) System.out.println(counts);
}
private static int distance_left(int left, ArrayList<Character> lst, int right) {
for (int i = left+1;i < right;i ++){
if (lst.get(i) == lst.get(right)) return i;
}
return 10000;
}
private static int distance_right(int left, ArrayList<Character> lst, int right) {
for (int i = right-1;i > left;i --){
if (lst.get(i) == lst.get(left)) return i;
}
return -100;
}
}
def distance_left(left,lst,right):
for i in range(left+1,right):
if lst[i] == lst[right]:return i
return 10000
def distance_right(left,lst,right):
for i in reversed(range(left+1,right)):
if lst[i] == lst[left]:return i
return -100
n = int(input())
lst = list(input())
counts,left,right = 0,0,n-1
flag2 = True
while left < right:
if lst[left] != lst[right]:
l = distance_left(left,lst,right)
r = distance_right(left,lst,right)
if l == 10000 and r == -100:
print("Impossible")
flag2 = False
break
if l-left <= right - r:
a = lst.pop(l)
lst.insert(left,a)
counts += l-left
else:
flag = False
if right != n-1:
flag = True
a = lst.pop(r)
if flag:lst.insert(right,a)
else:lst.append(a)
counts += right - r
left += 1
right -= 1
if flag2:print(counts)