標籤:style io ar color os sp for on div
前段時間一次聚會閑聊時聊到一個問題,就是給你一排數組,例如1,2,3,4,5,如何能高效的擷取上述數列的所有排列組合,正巧沒事,研究了一下,一開始以為是個很簡單的問題,就直接開始寫代碼了,後來發現怎麼迴圈也不理想,基本上都有一些不必要的消耗,百度一下看到一個不錯的演算法,字典序法,順便學習一下,然後記錄之。
摘一段演算法思想:
設P是[1,n]的一個全排列。
P=P1P2…Pn=P1P2…Pj-1PjPj+1…Pk-1PkPk+1…Pn , j=max{i|Pi<Pi+1}, k=max{i|Pi>Pj} ,對換Pj,Pk,將Pj+1…Pk-1PjPk+1…Pn翻轉, P’= P1P2…Pj-1PkPn…Pk+1PjPk-1…Pj+1即P的下一個
例子:839647521的下一個排列.
從最右開始,找到第一個比右邊小的數字4(因為4<7,而7>5>2>1),再從最右開始,找到4右邊比4大的數字5(因為4>2>1而4<5),交換4、5,此時5右邊為7421,倒置為1247,即得下一個排列:839651247.用此方法寫出全排列的非遞迴算
感覺還是挺明了的,在紙上稍微寫了一下,然後稍作驗證,確實不錯,然後自己用PHP實現了一下:
/* 字典序法擷取所有排列 @最後更新時間:03/05/2014 @toryzen(toryzen.com) @備忘,備忘中樣本用ABC順序表示 */ function getPars( $arr ){ //正向排列 sort( $arr ); //擷取數組長度 $len = count ( $arr )-1; //記錄傳入的排列 $return [] = $arr ; while (TRUE){ //從右側開始找到第一個左側(A)<右側(B)的數字序列 for ( $i = $len ; $i >=0; $i --){ if ( $arr [ $i ]> $arr [ $i -1]){ $here = $i -1; break ; } } //若找到了則開始換位 if ( $here >=0){ //從有右向左側找,第一個比左側(A)大的數字(C)交換位置得到CBA for ( $j = $len ; $j > $here ; $j --){ if ( $arr [ $here ]< $arr [ $j ]){ $revers = $j ; list( $arr [ $here ], $arr [ $j ]) = array ( $arr [ $j ], $arr [ $here ]); break ; } } //將後續數字倒序得到CAB unset( $newarr ); for ( $h = $here +1; $h <= $len ; $h ++){ $newarr [] = $arr [ $h ]; unset( $arr [ $h ]); } $return [] = $arr = array_merge ( $arr , array_reverse ( $newarr ,TRUE)); } else { break ; } } return $return ; } $arr = array (1,4,3,2); print_r(getPars( $arr )); |
除了這個還有一個遞迴法,But自己的遞迴學的不是很好,而且所有的遞迴都能用迴圈解決隨用迴圈,改天有時間,再研究一下遞迴,老是轉不過彎來。
PHP_字典序法獲得排列組合