【Algorithm】全排列演算法

TypantK發表於2019-03-09

題目描述:

輸入一個字串,按字典序列印出該字串中字元的所有排列。例如輸入字串abc,則列印出由字元a,b,c所能排列出來的所有字串abc,acb,bac,bca,cab和cba。

輸入描述:

輸入一個字串,長度不超過9(可能有字元重複),字元只包括大小寫字母。

https://www.nowcoder.com/practice/fe6b651b66ae47d7acce78ffdd9a96c7?tpId=13&tqId=11180&tPage=2&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking

 


全排列演算法-遞迴&字典序實現

原帖地址: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;
    }
    
}


 

相關文章