【Algorithm】全排列演算法
題目描述:
輸入一個字串,按字典序列印出該字串中字元的所有排列。例如輸入字串abc,則列印出由字元a,b,c所能排列出來的所有字串abc,acb,bac,bca,cab和cba。
輸入描述:
輸入一個字串,長度不超過9(可能有字元重複),字元只包括大小寫字母。
全排列演算法-遞迴&字典序實現
原帖地址:https://blog.csdn.net/u013309870/article/details/68941284#comments
全排列:
從n個不同元素中任取m(m≤n)個元素,按照一定的順序排列起來,叫做從n個不同元素中取出m個元素的一個排列。當m=n時所有的排列情況叫全排列。
例如:
1 、2 、3三個元素的全排列為:
{1,2,3},{1,3,2},{2,1,3},{2,3,1},{3,1,2},{3,2,1}。
解法1(遞迴)
如下圖:要對1、2、3、4進行排序,第一個位置上的元素有四種可能:1或2或3或4,假如已經確定了第一個元素為4,剩下的第二個位置上可以是1、2、3,很顯然這具有遞迴結構,如果原始要排列的陣列順序為1、2、3、4,現在只要分別交換1、2,1、3,1、4然後對剩下的3個元素進行遞迴的排列。
public void Permutation(char chs[],int start )
{
if(start==chs.length-1)
{
Arrays.toString(chs);
//如果已經到了陣列的最後一個元素,前面的元素已經排好,輸出。
}
for(int i=start;i<=chs.length-1;i++)
{
//把第一個元素分別與後面的元素進行交換,遞迴的呼叫其子陣列進行排序
Swap(chs,i,start);
Permutation(chs,start+1);
Swap(chs,i,start);
//子陣列排序返回後要將第一個元素交換回來。
//如果不交換回來會出錯,比如說第一次1、2交換,第一個位置為2,子陣列排序返回後如果不將1、2
//交換回來第二次交換的時候就會將2、3交換,因此必須將1、2交換使1還是在第一個位置
}
}
public void Swap(char chs[],int i,int j)
{
char temp;
temp=chs[i];
chs[i]=chs[j];
chs[j]=temp;
}
遞迴方法會對重複元素進行交換。
比如使用遞迴對{1,1}進行全排序會輸出:{1,1},{1,1}兩個重複的結果。要在排序的時候去掉重複結果,可以修改一下程式碼如下:
public static void Permutation(char chs[],int start)
{
if(start==end)
{
list.add(new String(chs));
}
for(int i=start;i<=chs.length-1;i++)
{
if(i==start||chs[i]!=chs[start])
{
//在排列的時候進行判斷如果後面的元素與start相同時就不進行排序。
//這樣就可以避免對重複元素進行排序
Swap(chs,i,start);
Permutation(chs,start+1);
Swap(chs,i,start);
}
}
}
解法2(字典序法)
對給定的字符集中的字元規定了一個先後關係,在此基礎上規定兩個全排列的先後是從左到右逐個比較對應的字元的先後。
列如:對a、b、c進行排序的結果是{a,b,c}、{a,c,b}、{b,a,c}、{b,c,a}、{c,a,b}、{c,b,a}
字典序法的優點是排列的結果按照順序輸出並且對於重複的元素不進行重複排序。
字典排序法的思想:
例如:對元素1,2,3,4進行排序,假設預設的陣列順序為{1,2,3,4},先輸出第一個排列:1、2、3、4。然後從右向左找到第一個非遞增的數,4,3,因為3比4小,交換3、4,並且對3後面的數進行逆序排列,第二個排列為{1,2,4,3},再從右向左3,4,2,發現2比4小,交換從右向左第一個比2大的數,交換後{1,3,4,2}再對3後面的數進行逆序排列第三個序列為:{1,3,2,4}
依次迴圈直到陣列成為完全遞減陣列結束1、2、3、4字典排序的最大序列為{4,3,2,1}。
public void PermutationWithDictionary(char chs[])
{
Arrays.sort(chs);
//先對陣列的元素進行依次排序
while(true)
{
System.out.println(chs);
int j=chs.length-1;
int index=0;
for(j=chs.length-2;j>=0;j--)
{
if(chs[j]<chs[j+1])
{
index=j;
break;
//從右向左找到第一個非遞增的元素
}
else if(j==0){
return;
}
}
for(j=chs.length-1;j>=0;j--)
{
if(chs[j]>chs[index])
break;
//從右向左找到第一個比非遞增元素大的元素
}
Swap(chs,index,j);
//交換找到的兩個元素
Reverse(chs,index+1);
//對非遞增元素位置後面的陣列進行逆序排列
}
}
public static void Reverse(char chs[],int i)
{
int k=i,j=chs.length-1;
while(k<j)
{
Swap(chs,k,j);
k++;
j--;
}
}
public static void Swap(char chs[],int i,int j)
{
char temp;
temp=chs[i];
chs[i]=chs[j];
chs[j]=temp;
}
開篇題目答案
package com.demo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class StringSort {
public static void main(String[] args) {
StringSort s = new StringSort();
ArrayList<String> list = s.Permutation2("dcba");
for(String str : list) {
System.out.print(str+"-");
}
System.out.println();
ArrayList<String> list2 = s.Permutation("dcba");
for(String str : list2) {
System.out.print(str+"+");
}
}
//遞迴
protected List<String> list = new ArrayList<String>();
public ArrayList<String> Permutation2(String str) {
if(str != null && str.length() != 0){
support(str.toCharArray(), 0);
Collections.sort(list);
}
return (ArrayList)list;
}
public void support(char[] cs, int start){
if(start == cs.length - 1){
list.add(String.valueOf(cs));
}else{
for(int j = start; j <= cs.length-1; j++){
if((j == start) || (cs[start] != cs[j])){
swap(cs, start, j);
support(cs, start+1);
swap(cs, start, j);
}
}
}
}
//字典序排列
public ArrayList<String> Permutation(String str) {
ArrayList<String> list = new ArrayList<String>();
if(str == null || str.length() == 0)return list;
char[] cs = str.toCharArray();
Arrays.sort(cs);
while(true){
list.add(String.valueOf(cs));
int start = 0;
int end = cs.length - 1;
for(int i = end - 1; i >= 0; i--){
if(cs[i] < cs[i+1]){
start = i;
break;
}else if(i == 0){
return list; //代表已經全部新增進list了
}
}
for(int j = end; j >= 0; j--){
if(cs[j] > cs[start]){
end = j;
break;
}
}
swap(cs, start, end);
reverse(cs, start+1);
}
}
public void reverse(char[] cs, int k){
int i = k;
int j = cs.length - 1;
while(i < j){
swap(cs, i, j);
i++;
j--;
}
}
public void swap(char[] cs, int i, int j){
char temp = cs[i];
cs[i] = cs[j];
cs[j] = temp;
}
}
相關文章
- 全排列演算法演算法
- 演算法——全排列演算法
- 全排列及相關擴充套件演算法(二)——求字典序下一組排列及全排列演算法套件演算法
- [演算法]全排列類問題演算法
- 前端電商 sku 的全排列演算法前端演算法
- 【演算法】遞迴實現全排列演算法遞迴
- 全排列演算法的JS實現演算法JS
- Java實現全排列、組合演算法Java演算法
- 字串全排列字串
- LeetCode46 回溯演算法求全排列,這次是真全排列LeetCode演算法
- 字串的全排列字串
- Algorithm演算法Go演算法
- Java實現-全排列Java
- [演算法] 固定的元素在固定長度上進行全排列演算法
- 請教一個關於全排列的演算法問題?演算法
- Day 28 | 491.遞增子序列 、46.全排列、 47.全排列 II
- JavaScript陣列元素全排列JavaScript陣列
- 字串全排列 java實現字串Java
- 演算法之路 - Way to Algorithm演算法Go
- (EM演算法)The EM Algorithm演算法Go
- php對陣列進行全排列的非遞迴演算法PHP陣列遞迴演算法
- Leetcode——46. 全排列LeetCode
- 【LeetCode】46. 全排列LeetCode
- leetcode:全排列(java回溯)LeetCodeJava
- js陣列全排列問題JS陣列
- 有重複元素的全排列
- LeetCode系列46—全排列LeetCode
- LeetCode-046-全排列LeetCode
- 維特比演算法(Viterbi Algorithm)維特比演算法ViterbiGo
- LeetCode-047-全排列 IILeetCode
- 遞迴解決全排列問題遞迴
- 實現自然數N的全排列
- 全排列價值(數學問題)
- 遺傳演算法 (Genetic Algorithm)演算法Go
- C++_STL—演算法Algorithm篇C++演算法Go
- Manacher's Algorithm 馬拉車演算法Go演算法
- 程式碼隨想錄演算法訓練營day29 | leetcode 491. 非遞減子序列、46. 全排列、47. 全排列 II演算法LeetCode
- 貪心演算法(貪婪演算法,greedy algorithm)演算法Go