利用遞歸求全排列的過程真的很難理解,先把代碼貼上來吧數組
function Permutation(str) { // write code here if(!str){ return str; } let len=str.length, result=[]; str=str.split('');// 字符串的索引屬性都是隻讀,後面要交換兩個字符的話仍是要先把字符串轉化爲數組 str.sort();// 直接把字符串按字典序排列了,後面求全排列時也會按照字典序 Permutate(str,0); result=[...new Set(result)];// 這裏是經過Set的特性去重,處理字符串中有重複字符的狀況 return result.toString();// 最後輸出的仍是字符串 function Permutate(str,index) { if(index===str.length){ let s=''; for(let i=0;i<str.length;i++){ s+=str[i]; }// 這裏是把數組從新轉回字符串 result.push(s); } else { for(let i=index;i<str.length;i++){ [str[index],str[i]]=[str[i],str[index]]; Permutate(str,index+1); } } } }
裏面有幾個坑要注意,一是經過字符串索引是不能修改字符串的,所以仍是要把字符串轉化爲數組;二是注意對重複字符的處理spa
回溯法相對來講更好理解一些,實際上就是對排列結果的每一位遍歷可能的取值。好比首先看第一位,它可能取到字符串裏的每個不重複字符,那麼就遍歷字符串按順序把每一個字符都安到第一位上。若是第一位取到了a,那麼再看第二位,就是從除去a的剩下的字符裏面取。若是字符所有被取完了,那麼將這個排列壓入結果數組裏,而後回溯到上一位。並且這個時候也要回復到上一位的狀態,就是把最後選擇的那個字符從排列裏去掉,從新壓回剩餘字符裏。code
function Permutation2(str){ // write code here if(!str){ return str; } let len=str.length, result=[], s=''; str=str.split(''); str.sort(); Permutate(str); result=[...new Set(result)]; return result.toString(); function Permutate(str) { if(str.length===0){ result.push(s); }else{ let marked=new Set(); for (let i=0;i<str.length;i++){ if (!marked.has([str[i]])){ let char=str.splice(i,1); s+=char; Permutate(str); str.splice(i,0,char);//把取的字符從新壓回剩餘字符裏 s=s.slice(0,s.length-1);//把取的字符從排列結果裏刪除 marked.add(char);//標記該字符已經被取過了 } } } } }