前言
傳送門,文章思路參考自柳神博客——https://blog.csdn.net/liuchuo/article/details/51990430
正文
問題描述
迴文串,是一種特殊的字符串,它從左往右讀和從右往左讀是一樣的。小龍龍認爲迴文串纔是完美的。現在給你一個串,它不一定是迴文的,請你計算最少的交換次數使得該串變成一個完美的迴文串。
交換的定義是:交換兩個相鄰的字符
例如mamad
第一次交換 ad : mamda
第二次交換 md : madma
第三次交換 ma : madam (迴文!完美!)
輸入格式
第一行是一個整數N,表示接下來的字符串的長度(N <= 8000)
第二行是一個字符串,長度爲N.只包含小寫字母
輸出格式
如果可能,輸出最少的交換次數。
否則輸出Impossible
樣例輸入
5
mamad
樣例輸出
3
AC代碼
/*
1.impossible的情況:如果有一個字符出現的次數是奇數次數,而且n是偶數,那麼不可能構成迴文
如果n是奇數,但是已經有一個字符出現的次數是奇數次數了,那麼如果又有一個字符是奇數次數,就不可能構成迴文。
2.如果n是奇數,計算中間那個字符交換的次數的時候,不需要模擬把這個數移動到中間去,因爲移動到中間的話假設有一對數都在左邊或者都在右邊,
那麼交換成迴文的時候就要經過中間,就會每次把cnt多加了1,而這個1是沒有必要的,因爲可以所有的迴文移動完了之後再把這個獨立的奇數移動過去,才能保證交換次數最少。
*/
#include<iostream>
#include<cstring>
using namespace std;
int main(){
int n,cnt=0;//cnt表示交換次數
string str;
cin>>n>>str;
int left,right=n-1;
bool isShow=false;//用於標記是否已經出現過奇數次數的字符
for(left=0;left<right;left++){
for(int i=right;i>=left;i--){//從後往前遍歷,匹配相同的字符
if(i==left){//說明字符str[left] 出現的次數爲奇數次
if(n%2==0||(n%2==1&&isShow==true)){//出現Impossible的兩種情況
cout<<"Impossible\n";
return 0;
}
isShow=true;
cnt+=n/2-left;//把字符str[left]移動到最中間需要移動的次數
} else if(str[i]==str[left]){//找到兩個相同的字符 ,將str[i]移動到與str[left]對應的位置 ,也就是將str[i]移動到right指示的位置
for(int j=i;j<right;j++){//這裏進行交換,爲了使j+1<n,即j<n-1,故right=n-1
swap(str[j],str[j+1]);
cnt++;
}
right--; //此時right位置上已經是換好的str[i],因此right繼續往左走
break;
}
}
}
cout<<cnt;
return 0;
}
後記
你強任你強