全排列的三种算法求解

 

import java.util.ArrayList;

/*
 * 编写一个方法,确定某字符串的所有排列组合。

 给定一个string A和一个int n,代表字符串和其长度,请返回所有该字符串字符的排列,
 保证字符串长度小于等于11且字符串中字符均为大写英文字符,
 
 
类似于解决合法括号的思路,遍历字符串,然后把每个字符插在前一个字符里已经得到的集合的每个字符串的的前面 后面 和里面
插入后都作为一个新的字符串添加进集合里


一共有字符的数量的阶乘个   比如abdc  一共有4!=24

 */
public class 全排列一 {
    public static void main(String[] args) {
        ArrayList<String> list = f2("abcd",3);
        int count = 0;
        for(String s:list) {
            System.out.println(++count+","+s);
        }
    }
    
    
    //逐步生成 迭代
    public static ArrayList<String> f1(String s){
        ArrayList<String> res = new ArrayList();
        
        res.add(s.charAt(0)+""); //把第一个字符插入作为初始
        
        for(int i=1;i<s.length();i++) {
            char c = s.charAt(i);
            ArrayList<String> res_new = new ArrayList();
            //遍历上一个字符之前得到的集合  然后对每一个字符串进行前 后 里的插入 都作为一个新的字符串添加进res_new这个集合
            for(String str:res) {
                res_new.add(c+str);//前面
                res_new.add(str+c);//后面
                
                //遍历str插在这个字符串里的每两字符之间
                for(int j=1;j<str.length();j++) {
                    res_new.add(str.substring(0, j)+c+str.substring(j));
                }
            }
            
            res = res_new;//赋值回给res,然后进行下一个字符的插入
        }
        
        return res;//返回res
    }
    
    
    //递归求解
    public static ArrayList<String> f2(String s,int cur){
        ArrayList<String> newList = new ArrayList();
        if(cur==0) {
            newList.add(s.charAt(0)+"");
            return newList;
        }
        
        ArrayList<String> oldList = f2(s,cur-1);
        char c = s.charAt(cur);
        for(String str:oldList) {
            newList.add(c+str);//前面
            newList.add(str+c);//后面
            
            //遍历str插在这个字符串里的每两字符之间
            for(int j=1;j<str.length();j++) {
                newList.add(str.substring(0, j)+c+str.substring(j));
            }
        }
        return newList;
        
    }
}

 

 

 

import java.util.ArrayList;
import java.util.Arrays;
/*
 * abc
 * 1:a跟a交换  不变  递归到b(k=1 i=1)  b跟b交换不变  递归调用到c(k=2,i=2) c跟c交换不变  再递归 调用k=3=arr.length 添加进res  
 * 然后回到 b  这时i=2 k=1  c跟b交换  这时是(acb),然后递归 k=2 b跟b交换 继续递归 k=3添加进res  
 * 然后回到 k=2 i=2  c跟b换回来(回溯)  保持原状态(abc)
 *
 * 然后回到一开始的最外层for循环  i=1 k=0 (b跟a)交换 然后继续递归下去  
 *
 *
 * 每次递归调用进入for循环第一次都是自身与自身交换 虽然不变 但是要确保添加进res里所以是有必要的
 * 因为可能上册的递归交换了位置 但后面的递归第一次交换都是自身与自身交换即使不变也是一种全排列
 *
 */
public class 全排列二 {
    
    
    public static void main(String[] args) {
        ArrayList<String> res = f2("abcd");
        for(String s:res) {
            System.out.println(s);
        }
    }
    
    
    public static ArrayList<String> f2(String s){
        ArrayList<String> res = new ArrayList<>();
        char[] arr = s.toCharArray();
        Arrays.sort(arr);
        getPermutationCore(arr,0,res);
        return res;
    }


    private static void getPermutationCore(char[] arr, int k, ArrayList<String> list) {
        if(k==arr.length) {
            list.add(new String(arr));
        }
        
        for(int i=k;i<arr.length;i++) {
            
            swap(arr,k,i);//把从K开始的每个字符都交换到K位置,
            
            //arr[i]交换到k位置后  后面的字符变动位置也是一种排列 所以递归调用自身把从K+1开始后的每个字符换到K+1位置
            getPermutationCore(arr,k+1,list);//递归调用下一个
            
            swap(arr,k,i);//要换回来 保持初始状态一样  这个叫回溯
        }
        
    }


    private static void swap(char[] arr, int k, int i) {
        char temp = arr[k];
        arr[k] = arr[i];
        arr[i] = temp;
        
    }
}

 

 

 

 

 

/*
 * LeetCode60 n个数的排列组合找出字典序的第k个排列
 * The set[1,2,3,…,n]contains a total of n! unique permutations.
 By listing and labeling all of the permutations in order,
 We get the following sequence (ie, for n = 3):
 "123"
 "132"
 "213"
 "231"
 "312"
 "321"

 Given n and k, return the k th permutation sequence.
 Note: Given n will be between 1 and 9 inclusive.

 时间限制:1秒
 
 前提原字符数组按字典序是有序的 如果获取的输入的数据时无序的 得要先排序
 
 因为每次都从头扫描 (原字符数组有序的前提下)  所以获得的全排列是按字典序的  所以要求第K个 计算到count==k便可输出了
 
 */


public class 全排列三 {
    static int count =0;
    public static void main(String[] args) {
        char[] arr = new String("acb").toCharArray();
        permutation("",arr,3);
    }
    
    public static void permutation(String prefix,char[] arr,int k) {
        if(prefix.length()==arr.length) {
            count++;
            if(count==k)
                System.out.println(k+":"+prefix);
            else
                System.out.println(prefix);
        }
        
        
        //每次从头扫描,只要该字符可用,就加到前缀里面,前缀就变长了  直到长度等于arr.length
        for(int i=0;i<arr.length;i++) {
            char c = arr[i];
            
            //如果前缀里c的个数少于原串那么就可以添加进去
            if(count(prefix,c)<count(arr,c)) {
                permutation(prefix+c,arr,k);
            }
        }
    }

    //计算c在原字符串一共有多少个
    private static int count(char[] arr, char c) {
        int cnt = 0;
        for(int i=0;i<arr.length;i++) {
            if(arr[i]==c)
                cnt++;
        }
        return cnt;
    }

    //计算字符c在前缀里出现了多少次
    private static int count(String prefix, char c) {
        int cnt = 0;
        for(int i=0;i<prefix.length();i++) {
            if(prefix.charAt(i)==c)
                cnt++;
        }
        return cnt;
    }
    
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值