国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > C > 正文

使用C語(yǔ)言解決字符串全排列問(wèn)題

2020-01-26 14:58:49
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

問(wèn)題
輸入一個(gè)字符串,打印出該字符串中字符的所有排列。例如輸入字符串a(chǎn)bc,則輸出由字符a,b,c所能排列出來(lái)的所有字符串a(chǎn)bc,acb,bac,bca,cab和cba

思路
這是典型的遞歸求解問(wèn)題,遞歸算法有四個(gè)特性:

  1.     必須有可達(dá)到的終止條件,否則程序陷入死循環(huán)
  2.     子問(wèn)題在規(guī)模上比原問(wèn)題小
  3.     子問(wèn)題可通過(guò)再次遞歸調(diào)用求解
  4.     子問(wèn)題的解應(yīng)能組合成整個(gè)問(wèn)題的解


對(duì)于字符串的排列問(wèn)題:
如果能生成n-1個(gè)元素的全排列,就能生成n個(gè)元素的全排列。對(duì)于只有一個(gè)元素的集合,可以直接生成全排列。所以全排列的遞歸終止條件很明確,只有一個(gè)元素時(shí)。我們可以分析一下全排列的過(guò)程:

  •     首先,我們固定第一個(gè)字符a,求后面兩個(gè)字符bc的排列
  •     當(dāng)兩個(gè)字符bc排列求好之后,我們把第一個(gè)字符a和后面的b交換,得到bac,接著我們固定第一個(gè)字符b,求后面兩個(gè)字符ac的排列
  •     現(xiàn)在是把c放在第一個(gè)位置的時(shí)候了,但是記住前面我們已經(jīng)把原先的第一個(gè)字符a和后面的b做了交換,為了保證這次c仍是和原先處在第一個(gè)位置的a交換,我們?cè)谀胏和第一個(gè)字符交換之前,先要把b和a交換回來(lái)。在交換b和a之后,再拿c和處于第一位置的a進(jìn)行交換,得到cba。我們?cè)俅喂潭ǖ谝粋€(gè)字符c,求后面兩個(gè)字符b、a的排列
  •     既然我們已經(jīng)知道怎么求三個(gè)字符的排列,那么固定第一個(gè)字符之后求后面兩個(gè)字符的排列,就是典型的遞歸思路了


下面這張圖很清楚的給出了遞歸的過(guò)程:

2015815112832632.png (805×385)

基本解決方法
方法1
:依次從字符串中取出一個(gè)字符作為最終排列的第一個(gè)字符,對(duì)剩余字符組成的字符串生成全排列,最終結(jié)果為取出的字符和剩余子串全排列的組合。

#include <iostream>#include <string>using namespace std; void permute1(string prefix, string str){  if(str.length() == 0)    cout << prefix << endl;  else  {    for(int i = 0; i < str.length(); i++)      permute1(prefix+str[i], str.substr(0,i)+str.substr(i+1,str.length()));  }} void permute1(string s){  permute1("",s);} int main(){  //method1, unable to remove duplicate permutations.  cout << "method1" << endl;  permute1("ABA");}

優(yōu)點(diǎn):該方法易于理解,但無(wú)法移除重復(fù)的排列,如:s="ABA",會(huì)生成兩個(gè)“AAB”。

方法2:利用交換的思想,具體見(jiàn)實(shí)例,但該方法不如方法1容易理解。

2015815112903993.gif (400×320)

#include <iostream>#include <string>#include <cstdio>using namespace std; void swap(char* x, char* y){  char tmp;  tmp = *x;  *x = *y;  *y = tmp;} /* Function to print permutations of string  This function takes three parameters:  1. String  2. Starting index of the string  3. Ending index of the string. */void permute(char *a, int i, int n){  int j;  if (i == n)   printf("%s/n", a);  else  {    for (j = i; j <= n; j++)    {     if(a[i] == a[j] && j != i) //為避免生成重復(fù)排列,當(dāng)不同位置的字符相同時(shí)不再交換       continue;     swap((a+i), (a+j));     permute(a, i+1, n);     swap((a+i), (a+j)); //backtrack    }  }}  int main(){  //method2  cout << "method2" << endl;  char a[] = "ABA";  permute(a,0,2);  return 0;}

兩種方法的生成結(jié)果:

method1ABAAABBAABAAAABABAmethod2ABAAABBAA

下面來(lái)看ACM題目實(shí)例

示例題目
題目描述

    題目描述: 
    給定一個(gè)由不同的小寫字母組成的字符串,輸出這個(gè)字符串的所有全排列。 
    我們假設(shè)對(duì)于小寫字母有'a' < 'b' < ... < 'y' < 'z',而且給定的字符串中的字母已經(jīng)按照從小到大的順序排列。 
    輸入: 
    輸入只有一行,是一個(gè)由不同的小寫字母組成的字符串,已知字符串的長(zhǎng)度在1到6之間。 
    輸出: 
    輸出這個(gè)字符串的所有排列方式,每行一個(gè)排列。要求字母序比較小的排列在前面。字母序如下定義: 
    已知S = s1s2...sk , T = t1t2...tk,則S < T 等價(jià)于,存在p (1 <= p <= k),使得 
    s1 = t1, s2 = t2, ..., sp - 1 = tp - 1, sp < tp成立。 
    樣例輸入: 
    abc 
    樣例輸出: 
    abc 
    acb 
    bac 
    bca 
    cab 
    cba 
    提示: 
    每組樣例輸出結(jié)束后要再輸出一個(gè)回車。

    ac代碼
   

 #include <stdio.h>   #include <stdlib.h>   #include <string.h>       struct seq   {     char str[7];   };       struct seq seqs[721];   int count;       void swap(char *str, int a, int b)   {     char temp;     temp = str[a];     str[a] = str[b];     str[b] = temp;   }       void permutation_process(char *name, int begin, int end) {     int k;         if (begin == end - 1) {       strcpy(seqs[count].str, name);       count ++;     }else {       for (k = begin; k < end; k ++) {         swap(name, k, begin);         permutation_process(name, begin + 1, end);         swap(name, k, begin);       }     }   }       int compare(const void *p, const void *q)   {     const char *a = p;     const char *b = q;     return strcmp(a, b);   }       int main()   {     char name[7];     int i, len;         while (scanf("%s", name) != EOF) {       count = 0;       len = strlen(name);       permutation_process(name, 0, len);       qsort(seqs, count, sizeof(seqs[0]), compare);           for (i = 0; i < count; i ++) {         printf("%s/n", seqs[i].str);       }       printf("/n");     }         return 0;   } 

       
    /**************************************************************
        Problem: 1120
        User: wangzhengyi
        Language: C
        Result: Accepted
        Time:710 ms
        Memory:920 kb
    ****************************************************************/ 

去掉重復(fù)的全排列
上述代碼有個(gè)缺陷,就是會(huì)造成重復(fù)數(shù)據(jù)的輸出,例如abb這種字符串,上述程序跑完結(jié)果如圖:

2015815112950326.png (564×150)

由于全排列就是從第一個(gè)數(shù)字起,每個(gè)數(shù)分別與它后面的數(shù)字交換,我們先嘗試加個(gè)這樣的判斷――如果一個(gè)數(shù)與后面的數(shù)字相同那么這兩個(gè)數(shù)就不交換了。例如abb,第一個(gè)數(shù)與后面兩個(gè)數(shù)交換得bab,bba。然后abb中第二個(gè)數(shù)和第三個(gè)數(shù)相同,就不用交換了。但是對(duì)bab,第二個(gè)數(shù)和第三個(gè)數(shù)不同,則需要交換,得到bba。由于這里的bba和開(kāi)始第一個(gè)數(shù)與第三個(gè)數(shù)交換的結(jié)果相同了,因此這個(gè)方法不行。

換種思維,對(duì)abb,第一個(gè)數(shù)a與第二個(gè)數(shù)b交換得到bab,然后考慮第一個(gè)數(shù)與第三個(gè)數(shù)交換,此時(shí)由于第三個(gè)數(shù)等于第二個(gè)數(shù),所以第一個(gè)數(shù)就不再用與第三個(gè)數(shù)交換了。再考慮bab,它的第二個(gè)數(shù)與第三個(gè)數(shù)交換可以解決bba。此時(shí)全排列生成完畢!

這樣,我們得到在全排列中去掉重復(fù)的規(guī)則:
去重的全排列就是從第一個(gè)數(shù)字起,每個(gè)數(shù)分別與它后面非重復(fù)出現(xiàn)的數(shù)字交換。

貼出上面ac代碼的去重版本:
   

 #include <stdio.h>   #include <stdlib.h>   #include <string.h>      struct seq   {     char str[7];   };      struct seq seqs[721];   int count;      int is_swap(char *str, int begin, int k)   {     int i, flag;        for (i = begin, flag = 1; i < k; i ++) {       if (str[i] == str[k]) {         flag = 0;         break;       }     }        return flag;   }      void swap(char *str, int a, int b)   {     char temp;     temp = str[a];     str[a] = str[b];     str[b] = temp;   }      void permutation_process(char *name, int begin, int end) {     int k;        if (begin == end - 1) {       strcpy(seqs[count].str, name);       count ++;     }else {       for (k = begin; k < end; k ++) {         if (is_swap(name, begin, k)) {           swap(name, k, begin);           permutation_process(name, begin + 1, end);           swap(name, k, begin);         }       }     }   }      int compare(const void *p, const void *q)   {     const char *a = p;     const char *b = q;     return strcmp(a, b);   }      int main()   {     char name[7];     int i, len;        while (scanf("%s", name) != EOF) {       count = 0;       len = strlen(name);       permutation_process(name, 0, len);       qsort(seqs, count, sizeof(seqs[0]), compare);          for (i = 0; i < count; i ++) {         printf("%s/n", seqs[i].str);       }       printf("/n");     }        return 0;   } 

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表

圖片精選

主站蜘蛛池模板: 长垣县| 鲁山县| 平陆县| 双牌县| 晋宁县| 祁阳县| 文水县| 华亭县| 边坝县| 洛宁县| 丘北县| 清徐县| 汉中市| 江都市| 日照市| 左贡县| 藁城市| 马鞍山市| 仁寿县| 礼泉县| 梁山县| 平和县| 集安市| 象山县| 吉木萨尔县| 汤原县| 八宿县| 姜堰市| 沙湾县| 拉萨市| 罗山县| 合川市| 新巴尔虎右旗| 南京市| 阆中市| 仪陇县| 招远市| 郸城县| 密山市| 建昌县| 彭水|