對於給定的集合a,其中的n個元素互不相同,如何輸出這n個元素的所有排列(全排列)。
例如:給定集合[1,2,3] 它的全排列子集為:
[ [1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
思路:1.保持第乙個數不變,對後面的數進行全排列
2.將第乙個數換成其它數,對後面的數進行全排列
3.第乙個數所有情況遍歷遍歷完成,得到全排列
例如:【1,2,3,4】
對1開頭的所有排列,得到【1,2,3,4】【1,2,4,3】【1,3,2,4】【1,3,4,2】【1,4,2,3】【1,4,3,2】
對2開頭的所有排列….依次類推
public list> permute(int nums)
if(nums.length==0)
helper(nums,permutation,set,result);
return result;
}public
void
helper(int nums,listpermutation,
setset,list> result)
for(int i=0;iif(permutation.contains(nums[i]))
continue;
permutation.add(nums[i]);
set.add(nums[i]);
helper(nums,permutation,set,result);
set.remove(nums[i]);
permutation.remove(permutation.size()-1);}}
注意:此方法對於有重複元素的集合無效
為什麼需要兩個集合來儲存資料?
1.list不適合隨機訪問,適合順序訪問,remove(index)
2.list適合隨機訪問,不適合遍歷,remove(value)
3.indexoutofbound***ception錯誤提醒我們:使用remove()的方法時,要先從大到小的位置移除。當然如果你知道具體的物件,直接移除remove(物件)更穩妥。
思路:演算法如下:1.對初始佇列進行排序,找到所有排列中最小的乙個排列pmin。
2.找到剛剛好比pmin大比其它都小的排列p(min+1)。
3.迴圈執行第二步,直到找到乙個最大的排列,演算法結束。
如排列12345,這是所有排列中最小的乙個排列,剛好比12345大的排列是:12354。
給定已知序列p = a1a2a3…..an
對p按字典排序,得到p的乙個最小排列pmin = a1a2a3….an ,滿足ai > a(i-1) (1 < i <= n)
從pmin開始,找到剛好比pmin大的乙個排列p(min+1),再找到剛好比p(min+1)大的乙個排列,如此重複。
1.從後向前(即從an->a1),找到第一對為公升序的相鄰元素,即ai < a(i+1)。
若找不到這樣的ai,說明已經找到最後乙個全排列,可以返回了。
2.從後向前,找到第乙個比ai大的數aj,交換ai和aj。
3.將排列中a(i+1)a(i+2)….an這個序列的數逆序倒置,即an…..a(i+2)a(i+1)。因為由前面第1、2可以得知,a(i+1)>=a(i+2)>=…..>=an,這為乙個公升序序列,應將該序列逆序倒置,所得到的新排列才剛剛好比上個排列大。
4.重複步驟1-3,直到返回。
這個演算法是c++ stl演算法next_permutation的思想。
(盜來的圖,哈哈哈)
//排序
insertionsort(nums);
listarray= new arraylist();
for (int t : nums)
list.add(array);
int i;
while((i=hasnext(nums))>0)
j++;
}swap(nums,i-1,k);
//反轉
reverse(nums,i,nums.length-1);
listarr= new arraylist();
for (int t : nums)
list.add(arr);
}return list;
}public
inthasnext(int nums)
}return
0; }
public
void
reverse(int nums,int i,int j)
public
void
insertionsort(int arr)
arr[preindex+1] = current;
}
}使用字典序輸出集合的全排列需要注意,因為字典序涉及兩個排列之間的比較,對於元素集合不方便比較的情況,可以將它們在陣列中的索引作為元素,按照字典序生成索引的全排列,然後按照索引輸出對應集合元素的排列,示例**使用的就是此方法。對於集合a,可以對其索引1234進行全排列生成。這麼做還有乙個好處,就是對於字典序全排列生成演算法,需要從字典序最小的排列開始才能夠生成集合的所有排列,如果原始集合a中的元素不是有序的情況,字典序法將無法得到所有的排列結果,需要對原集合排序之後再執行生成演算法,生成索引的全排列,避免了對原始集合的排序操作。
字典序演算法還有乙個優點,就是不受重複元素的影響。例如1224,交換中間的兩個2,實際上得到的還是同乙個排列,而字典序則是嚴格按照排列元素的大小關係來生成的。對於包含重複元素的輸入集合,需要先將相同的元素放在一起,以集合a為例,如果直接對其索引123456進行全排列,將不會得到想要的結果,這裡將重複的元素放到相鄰的位置,不同元素之間不一定有序,得到排列a』,然後將不同的元素,對應不同的索引值,生成索引排列122334,再執行全排列演算法,即可得到最終結果。
全排列 遞迴與非遞迴實現
全排列問題在公司筆試的時候非經常見,這裡介紹其遞迴與非遞迴實現。簡單地說 就是第乙個數分別以後面的數進行交換 e.g e a b c 則 prem e a.perm b,c b.perm a,c c.perm a,b 然後a.perm b,c ab.perm c ac.perm b abc acb....
全排列的遞迴與非遞迴實現
1 全排列 將n個不同元素按照不同的順序進行排列,一般要求所有的排列方式,或者滿足某些要求的排列方式,比如先後順序的限制 2 遞迴實現全排列 eg 對 a b c d 進行全排列,可以按照以下的步驟 1.a後面加上 b c d 的全排列 2.b後面加上 a c d 的全排列 3.c後面加上 b a ...
全排列的遞迴與非遞迴實現
問題 輸入乙個序列 元素無重複 輸出其全排列 一般採用經典的遞迴解法,後來想將其改造為非遞迴 思考很久後覺得並不好寫,手工模擬遞迴棧的行為容易出錯。然後上網搜尋了一下眾的非遞迴 發現很多人的非遞迴 是各種全新的求解演算法,而不是相同演算法的非遞迴實現,和我想要的不一樣。遞迴解法 假設輸入序列 0,1...