乙個演算法命題:給定字串s[0…n-1],設計演算法,列舉s的全排列。如:123,全排列就是:123,132,213,231,312,321
由123的全排列:123,132,213,231,312,321可知,這個全排列大小是有序的。也就是說,從最小的開始排列,每次只找比當前排列大一點的序列即可,這也是核心。
起點:字典序最小的排列,例如12345
終點:字典序最大的排列,例如54321
乙個演進:
逐位考察哪個能增大:乙個數右面有比它大的數存在,它就能增大。
那麼最後乙個能增大的數是——x = 1,1應該增大到多少?
增大到它右面比它大的最小的數——y = 3
應該變為23***。 顯然,***應由小到大排:145 , 得到23145
步驟:後找、小大、交換、翻轉——
後找:字串中最後乙個公升序的位置i,即:s[k]>s[k+1](k>i),s[i]
查詢(小大):s[i+1…n-1]中比ai大的最小值sj;
交換:si,sj;
翻**s[i+1…n-1]; 為什麼要翻轉?因為交換操作後,s[i+1…n-1]一定是降序的
以上是官話,比較難理解,我的理解如下
過程化:整理成演算法語言步驟:後找、小大、交換、翻轉——
後找、查詢:從倒數第二位開始作為基礎位置,找基礎位置後的比基礎位置上的數大的且最小的數
交換:交換基礎位置上的數 和 找到的比基礎位置大的最小的數
翻**將基礎位置之後的數反轉。因為此時基礎位置後的數一定是降序的,要讓它成為公升序
/*有序序列的全排列演算法*/
void allsequence(char s)else
} }/**
* 獲得字串序列中兩個交換位置,這兩個位置上的數交換後,可以增大該字串序列。這裡獲得的就是能最小增大的兩個交換位置。
* 例如:1342,那麼找兩個位置上的數交換後能讓他增大。那基礎位置就可以從倒數第二個數開始,然後從基礎位置往後找,
* 若找到比基礎位置上的數大的數,那此時交換兩個數就能增大這個序列。並且要找到比基礎位置上的數大並且是所有比它大的最小的數
* @param str
* @return 返回的int[2]陣列元素。0位置元素記錄交換的左邊位置,1位置元素記錄交換的右邊位置
*/int getswapfromandtoindex(char str)
}if(++afterbasis > str.length - 1)else
}} return null; }
void swapchar(char s, int i, int j)
/**反轉。把字元陣列從from位置開始後的數反轉*/
void revertstr(char str, int from)
for(int i = from; i < (str.length + from)/2;i++) }
public static void main(string args)
注:以上**是放在類strremove中,所有strremove s1 = new strremove()來準備呼叫方法
最終結果:
123
132213
231312
321-------------------------------------
1223
1232
1322
2213
2231
2312
2321
3122
3221
相對於遞迴實現的全排序演算法稍微複雜些,但是深度不大。非遞迴實現的恰好免疫有重複序列的全排序,不會重複;例如**中測試的1223序列,不會產生多餘的全排序
另一實現:字串全排列-遞迴實現
C 演算法 字串全排列 非遞迴 非遞迴
字串的全排列是面試中相對而言必要重要的演算法,有兩種實現方法 遞迴,非遞迴 替換點 從字串的最後一位開始,找到第乙個逆序的字串,如 54312 那麼從後向前第乙個逆序為12,那個1就是替換值,替換值得位置就是替換點。非遞迴演算法思想 對於乙個字串4231,這個字串中排列組合中1234是最小的數,43...
遞迴 字串全排列 全排列
在高中階段我們已經通過大量的習題了解了排列和組合。但是有時候我們研究的不是由排列和組合算出來的數字,研究的是生成排列和組合。即,把集合中元素所有的排列和組合全部列出來,然後研究這些序列的性質。今天我用兩種方法講一下如何生成排列。注意我們這裡涉及的順序都是序列的字典序。序列的字典序 設有兩個序列,第乙...
字串的全排列詳解,遞迴 非遞迴
輸入乙個字串,列印出該字串中字元的所有排列。例如輸入字串abc,則輸出由字元a,b,c所能排列出來的所有字串abc,acb,bac,bca,cab和cba 首先,我們固定第乙個字元a,求後面兩個字元bc的排列 當兩個字元bc排列求好之後,我們把第乙個字元a和後面的b交換,得到bac,接著我們固定第乙...