Description
回文串,是一種特殊的字符串,它從左往右讀和從右往左讀是一樣的。
小龍龍認為回文串才是完美的。現在給你一個串,它不一定是回文的,請你計算最少的交換次數使得該串變成一個完美的回文串。
交換的定義是:交換兩個相鄰的字符
例如: mamad
第一次交換 ad : mamda;
第二次交換 md : madma;
第三次交換 ma : madam (回文!完美!)
Input
第一行是一個整數N,表示接下來的字符串的長度(N ≤ 8000)。
第二行是一個字符串,長度為N.只包含小寫字母。
Output
如果可能,輸出最少的交換次數。
否則輸出Impossible。
Sample Input
5
mamad
Sample Output
3
#include<stdio.h> int main(){ int n;//代表要輸入的字符長度 int flag=0;//用來標記是否出現了不能匹配的單個字符 int count=0;// 用來表示最少的交換次數 int j;//用來盛放n-1的值,僅是為了方便 char a[8005];//用來盛放字符串 char t;//用於字符的交換 scanf("%d",&n);//輸入n scanf("%s",a);//輸入字符串 j=n-1; for(int i=0;i<j;i++){//從下標為i的字符開始,到下標為【j-1】的字符結束,依次固定字符 for(int k=j;k>=i;k--){//然后從下標為j的字符開始,到下標為i的結束(也就是從后往前)依次與固定的字符作比較 if(i==k){//當固定的字符在字符串中沒有找到能與它匹配的字符時 if(n%2==0||flag){//判斷字符串的長度是不是偶數,或者flag的值是否為1 printf("Impossible");//如果滿足這兩個條件中的任意一個,那么這個字符不可能是回文串,輸出Impossible結束即可 return 0; } flag=1;//如果字符串長度為奇數並且flag的值為0,就將flag賦值為1 ,代表出現了不能匹配的單個字符 count+=n/2-i;//count的值加上n/2-i ,n/2-i代表這個單個字符移到字符串中間位置的步數 } else if(a[i]==a[k]){// 如果兩個字符相同,即固定的字符在后面找到了與它能匹配的字符 for(int b=k;b<j;b++){//將a[k]這個字符移到a[j]的位置 t=a[b];//交換過程 a[b]=a[b+1]; a[b+1]=t; count++;//每交換一次,count自增1 } j--;//當固定的字符找到能與它匹配的字符時,j自減1 ,這一步很關鍵 break;// 當固定的字符找到能與它匹配的字符時,跳出第二層循環,第一層循環繼續固定下一個字符 } } } printf("%d",count);//輸出count的值 return 0; }
有幾個問題詳細解釋一下:
一: 如果在回文串里有兩個字符相同,我們就暫且稱呼這兩個字符相互匹配
二: 回文串的特點:如果回文串的長度為偶數,那么回文串里任何一個字符都能找到與之匹配的字符,如果回文串的長度為奇數,那么回文串里只能有一個字符是不能匹配的,大家仔細想一想這個特點。
三:關於代碼中第 25 行為何要判斷長度是否為偶數:當出現不能匹配的字符時,才會判斷這個條件。因為回文串長度為偶數時,任何一個字符都是可匹配的,所以,當字符串中出現不可匹配的字符並且字符長度為偶數時,該字符串一定不是回文串。只有奇數長度的回文串才會出現不可匹配的字符,並且只能有一個不能匹配的字符。
四:關於代碼中第 25 行為何要判斷 flag 是否為 1:當出現不能匹配的字符時,才會判斷這個條件。flag 為 1 代表字符串中已經出現了一個不可匹配的字符,當出現不能匹配的字符並且 flag 為 1 時,代表這個字符串里有兩個不可匹配的字符,這與回文串的特點不符,所以該字符串一定不是回文串。
五:j--與 i++幾乎是同時發生的,我們可以這樣理解,當字符串中的第一個字符與最后一個匹配好了的話,我們就暫時將他們舍棄,先不管他們,只看他們中間的字符就行,
用幾個例子來理解一下過程:
樣例一:mamad
1
首先在這里,代碼中的 n 為 5,j 為 4,i 為 0,然后固定下標為 i 的字符,此時 i 為 0,即字符 m,然后從下標為 j 的字符開始,也就是從字符 d 開始,依次向前與 m 作比較,
字符 d 與字符 m 不相同,繼續向前走,
走到字符 a字符 a 與字符 m 仍然不相同,繼續向前走,
走到字符 m字符 m 與字符 m 相同,
這時,將第二個 m 移到下標為 j 的字符的地方,也就是字符 d 那里,首先 m 與 a 交換位置,count 自增 1,字符串變為 maamd,然后 m 與 d 交換位置,count 自增1,字符串變為 maadm,交
換步驟完成這時,j 會自減 1,j 變為 3,同時 break 跳出第二層循環,第一層循環的 i 自增 1,i 變為1
2
這時繼續固定字符,固定下標為 i 的字符,此時 i 為 1,也就是字符 a,然后從下標為 j的字符開始,此時 j 為 3,也就是從字符 d 開始,依次向前與 a 作比較
字符 d 與字符 a 不相同,繼續向前走,走到字符 a
字符 a 與字符 a 相同,這時,將第二個 a 移到下標為 j 的地方,也就是字符 d 那里,字符 a與字符 d 交換位置,count 自增 1,字符串變為 madam,交換步驟完成
這時,j 會自減 1,j 變成 2,同時 break 跳出第二層循環,第一層循環的 i 自增 1,i 變為2
3
這時,繼續執行第一層循環,發現 i=j=2,不符合循環條件,跳出循環,輸出 count 的值,
count 共自增三次,所以輸出 3.
樣例二:accc
首先在這里,代碼中的 n 為 4,j 為 3,i 為 0,然后固定下標為 i 的字符,此時 i 為 0,即字符 a,然后從下標為 j 的字符開始,也就是從字符 c 開始,依次向前與 a 作比較,
字符 c 與字符 a 不相同,繼續向前走,走到字符 c
字符 c 與字符 a 不相同,繼續向前走,走到字符 c
字符 c 與字符 a 不相同,繼續向前走,走到字符 a
這時,代碼中 i 的值與 k 的值相同,字符 a 在字符串中找不到能與它匹配的字符,這時,判斷字符長度是否為偶數或者 flag 是否為 1,這時發現字符長度為偶數,那么該字符串一定不是回文串。
樣例三:abc
1
首先在這里,代碼中的 n 為 3,j 為 2,i 為 0,然后固定下標為 i 的字符,此時 i 為 0,即字符 a,然后從下標為 j 的字符開始,也就是從字符 c 開始,依次向前與 a 作比較
字符 c 與字符 a 不相同,繼續向前走,走到字符 b
字符 b 與字符 a 不相同,繼續向前走,走到字符 a
這時,發現字符 a 在字符串中找不到能與它匹配的字符,這時,判斷字符長度是否為偶數或者 flag 是否為 1,這時發現字符長度為奇數,並且 flag 為初始值 0,這時將 flag 賦值為1,count+= n/2-i,n/2-i 這里的值為 1,代表將字符 a 移到字符串中間所需要的步驟,注意一下,這時並不用真的將字符 a 移到字符串中間,只需加上所需步驟即可
2
這時,i 自增 1,變為 1,j 仍為 2,然后繼續固定下標為 i 的字符,即固定字符 b,從下標為 j 的字符開始,也就是從字符 c 開始,依次向前與 b 作比較
字符 c 與字符 b 不相同,繼續向前走,走到字符 b
這時,i 的值與 k 的值相同,判斷字符長度是否為偶數或者 flag 是否為 1,發現字符長度為奇數,flag 為 1,代表此時已經發現了兩個不可匹配的字符,那么該字符串不可能為回文串。
