字串的全排列 遞迴演算法訓練

2021-06-20 15:34:42 字數 2541 閱讀 5715

前幾天,師兄輕描淡寫的出了一道題,對於乙個給定的字串,輸出它的全排列結果,例如,輸入ab,則程式需要輸出ab,ba[結果數為2*1=2]。額外的要求是對於字串中的重複字元,程式要能識別出來並進行去重處理,例如,輸入aab,則程式需要輸出baa,aba,aab[結果數為3,而不是3*2=6]。

這裡我用了兩種思路實現了這道題,不過都屬於遞迴,第一種思路是我自己想的,只能輸出全排列,在去重處理上尚需完善[例如,輸入aab,程式可以得到正確結果;但如果輸入aaba,程式就得不到完全去重的結果了,即重複字元只能連續出現,否則程式就會出現bug,究其原因還是遞迴時記不住以前處理的結果,如果記錄這些結果,則空間開銷太大,而且每次都要檢查是否與以前的結果相同,付出的時間代價也很大] 。

第二種思路是另一位師兄指點我的,在他提出的方案基礎上,我做了完善,不但可以輸出全排列,而且可以達到去重要求,算是乙個完整的演算法。

第一種思路:求字串a的全排列,可以分解為求a的全排列,對於a的每乙個全排列結果,只要將a[n]插入到a序列的n個位置中,即可得到a的全排列結果。例如:求abc的全排列,可以先求ab的全排列,再將c插入到第0,1,2位即可得到abc的全排列,而對於ab的全排列,可以先求a的全排列,再將b插入到第0,1位即可得到ab全排列結果,因為a是單個字元,它的全排列結果只有乙個:a,所以遞迴開始返回,層層向上,得到abc的全排列的解。總結:這是基於插入操作的演算法!

第二種思路:求字串a的全排列,首先將a[0]和a[n]調換,然後求前面長度為n - 1的字串的全排列,完成後,將a序列恢復原樣,再將a[1]和a[n]調換,以此類推,直到a[n]和a[n]調換,去求前面長度為n - 1的字串的全排列,至此所有的結果均已得到。例如:求abc的全排列,可以先將a和c調換並固定a,即cba,此時求cb的全排列,將c和b調換並固定c,即bca,由於b是乙個單獨的字串,此次遞迴到底層,輸出乙個結果bca,返回,回歸原樣為cba,此時下乙個需要處理的值是b,即b和b調換【即a[i]和a[n]調換,但此時i恰好等於n】,得到cba,由於c是單獨的字串,遞迴到底層,輸出乙個結果cba,返回,回歸原樣為cba,因為i已經等於n,則繼續返回,回歸原樣abc,此時a已經處理完畢,再將b放在最末尾固定,進行處理,以此類推,得到所有全排列結果。這個思路有乙個好處,即付出少量的空間代價即可達到去重處理的要求,對於重複的字元,程式只要發現這個字元曾經在i位置固定過,就不再進行此輪處理,因為對於任意字元m,在i位置固定過,則可知m在i位置的前提下整個字串的全排列結果已經得到,那麼相同的字元再一次固定在相同的位置,處理的全排列必然導致結果重複。總結:這是基於調換操作的演算法!

第一種思路的源**【不完整,去重還有bug】:

#include #include #include int count = 0;//結果數目

void insert(char *a, int nowlength, char b)//將字元b插入到長度為nowlength的字串中的0,1,2,...,nowlength位置

//記住a的原樣,b每一輪插入操作得到結果後,在進行下一輪操作時a要恢復原樣

temp[i] = '\0';

for(j = 0; j <= nowlength; j ++)

//恢復操作

if(a[j] == b)//發現相同元素,只能留一次排列,其餘相同的去除,這個只能處理aaab型的,不能處理aaba型的

else}}

else

for(i = nowlength; i > j; i --)

a[j] = b;//插入操作

j += step;

if(nowlength + 1 < strlen(a))

else

}}int main()

else

}return 0;

}

第二種思路【完整,可全排列亦可去重】:

#include #include #include int count = 0;

typedef struct

alphabet;//字母表結構體,用雜湊表的形式做記錄,可以讓查詢時間縮短至o(1)。

void wholearray(char *a, char nowlength, alphabet *records)

//遞迴到底層,輸出結果

else

else

}}//用temp表複製records表,並傳入到遞迴的下一層中,以免破換records的值,因為records只有在最頂級的迴圈處理中才能更改,它表示某乙個字元所有的全排列結果都已得到

wholearray(a, nowlength - 1, temp);

a[i] = a[nowlength - 1];

a[nowlength - 1] = guard;//返回上層遞迴時要將區域性字串回歸原樣}}

}}int main()

for(i = 0; i < strlen(a); i ++)}}

count = 0;

wholearray(a, strlen(a), records);

printf("count = %d\n", count);

}return 0;

}

字串全排列演算法 遞迴

以字串1234為例 1 一 234 2 一 134 3 一 214 4 一 231 如何才能保證不遺漏呢 如下 includeusing namespace std char str 1234 int size sizeof str sizeof char str 要進行全排列的字元陣列 size ...

遞迴 字串全排列 全排列

在高中階段我們已經通過大量的習題了解了排列和組合。但是有時候我們研究的不是由排列和組合算出來的數字,研究的是生成排列和組合。即,把集合中元素所有的排列和組合全部列出來,然後研究這些序列的性質。今天我用兩種方法講一下如何生成排列。注意我們這裡涉及的順序都是序列的字典序。序列的字典序 設有兩個序列,第乙...

字串的全排列 遞迴演算法

題目 給定字串s 0.n 1 設計演算法,列舉s的全排列。假設字串為 1234 首先考慮1,然後問題就變成了考慮 234 的全排列,所以問題規模縮小了1,然後再考慮2,依次類推。可以採用遞迴演算法。1 234 2 134 3 124 4 123 假設有重複字元,則重複字元的全排列就是每個字元分別與它...