問題描述
回文串,是一種特殊的字符串,它從左往右讀和從右往左讀是一樣的。小龍龍認為回文串才是完美的。現在給你一個串,它不一定是回文的,請你計算最少的交換次數使得該串變成一個完美的回文串。
交換的定義是:交換兩個相鄰的字符
例如mamad
第一次交換 ad : mamda
第二次交換 md : madma
第三次交換 ma : madam (回文!完美!)
輸入格式
第一行是一個整數N,表示接下來的字符串的長度(N <= 8000)
第二行是一個字符串,長度為N.只包含小寫字母
輸出格式
如果可能,輸出最少的交換次數。
否則輸出Impossible
樣例輸入
5
mamad
樣例輸出
3
算法思路
由問題描述可以得知,有兩種情況會輸出“Impossible”,一種是當字符串長度為奇數且出現兩個及兩個以上出現次數為奇數個的字符,另一種是字符串長度為偶數但存在出現次數為奇數個的字符。當字符串具備構成一個完美的回文串條件時,我們可以從最左邊的元素開始查找,然后從右向左查找能夠和最左邊元素匹配的字符,若匹配成功則將該字符交換至字符串的最右邊,然后將從右邊查找的標記下標減一並從緊鄰最左邊的第二個字符開始再次查找,依次類推直至兩個索引標記相等。
算法實現
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int num = input.nextInt();
String s = input.next();
int oldNum = 0;//判斷是否已經存在一個單獨的奇數個數的字符了
int cnt = 0;//總共交換次數
int end = num - 1;//字符串最后一個字符的下標
char[] chars = s.toCharArray();
for (int i = 0; i < end; i++) {
for (int j = end; j >= i; j--) {
if(i == j){//chars[i]未找到與之相等的字符
if(num % 2==0 || oldNum == 1){//字符串長度為偶數個且存在出現次數為奇數個的字符或者存在兩個出現次數為奇數個的字符
System.out.println("Impossible");
return;
}
oldNum = 1;//字符串長度為奇數且找到一個字符出現的次數為奇數
cnt += num / 2 - i;//將奇次字符交換到中間位置的次數
}
if(chars[i]==chars[j]){//如果找到了,將chars[j]交換到最后
for (int k = j; k < end; k++) {
char t = chars[k];
chars[k] = chars[k + 1];
chars[k + 1] = t;
cnt++;
}
end--;//末尾遞減
break;
}
}
}
System.out.println(cnt);
}
}