完美的代價


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

 

這時繼續固定字符,固定下標為 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

 

這時,繼續執行第一層循環,發現 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,代表此時已經發現了兩個不可匹配的字符,那么該字符串不可能為回文串。

 
        


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM