全排列(四种方法java版本)

全排列(四种方法)

1.逐步生成大法-迭代法

1.1思路图解

通过在每个位置上插入新字符实现全排列
在这里插入图片描述

1.2代码实现

1.2.1核心代码
  public ArrayList<String> getPermutation0(String A) {
    int n = A.length();
    ArrayList<String> res = new ArrayList<>();
    res.add(A.charAt(0) + "");//初始化,包含第一个字符

    for (int i = 1; i < n; i++) {//第二个字符插入到前面生成集合的每个元素里面
      ArrayList<String> res_new = new ArrayList<>();
      char c = A.charAt(i);//新字符
      for (String str : res) {//访问上一趟集合中的每个字符串
        //  插入到每个位置,形成一个新串
        String newStr = c + str;//加在前面
        res_new.add(newStr);
        newStr = str + c;//加在后面
        res_new.add(newStr);
        //加在中间
        for (int j = 1; j < str.length(); j++) {
          newStr = str.substring(0, j) + c + str.substring(j);
          res_new.add(newStr);
        }
      }
      res = res_new;//更新

    }
    return res;
  }
1.2.2完整代码(复制即可运行)
package LanQiao;

import java.util.ArrayList;

public class Demo17 {
  public static void main(String[] args) {
    ArrayList<String> res = new Demo17().getPermutation0("abc");
    System.out.println(res.size());
    System.out.println(res);
  }

  /*逐步生成大法-迭代法*/
  public ArrayList<String> getPermutation0(String A) {
    int n = A.length();
    ArrayList<String> res = new ArrayList<>();
    res.add(A.charAt(0) + "");//初始化,包含第一个字符

    for (int i = 1; i < n; i++) {//第二个字符插入到前面生成集合的每个元素里面
      ArrayList<String> res_new = new ArrayList<>();
      char c = A.charAt(i);//新字符
      for (String str : res) {//访问上一趟集合中的每个字符串
        //  插入到每个位置,形成一个新串
        String newStr = c + str;//加在前面
        res_new.add(newStr);
        newStr = str + c;//加在后面
        res_new.add(newStr);
        //加在中间
        for (int j = 1; j < str.length(); j++) {
          newStr = str.substring(0, j) + c + str.substring(j);
          res_new.add(newStr);
        }
      }
      res = res_new;//更新

    }
    return res;
  }
}

1.3运行结果

在这里插入图片描述

2.多路递归

2.1思路图解

先确定第一个元素,后面的的再进行排序(遵循先纵后横的原则)
利用了回溯的思想,每层对括号中的每一个元素,取出来加入已经选择的集合,这样成为了下一层。
后面的层都遵循这样的逻辑,直到括号内没有元素。
但是需要保留父亲的状态才能得到其他的支路(因为父节点是共享的)
在这里插入图片描述

2.2代码实现

package LanQiao;

import java.util.ArrayList;
import java.util.Arrays;

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

 给定一个string A和一个int n,代表字符串和其长度,请返回所有该字符串字符的排列,
 保证字符串长度小于等于11且字符串中字符均为大写英文字符,

 排列中的字符串按字典序从大到小排序。(不合并重复字符串)
 */
public class Demo18 {
  public static void main(String[] args) {
    ArrayList<String> res = new Demo18().getPermutation("ABC");
    System.out.println(res.size());
    System.out.println(res);
  }

  ArrayList<String> res = new ArrayList<>();

  public ArrayList<String> getPermutation(String A) {
    char[] arr = A.toCharArray();
    Arrays.sort(arr);//abc
    getPermutationCore(arr, 0);
    return res;
  }

  private void getPermutationCore(char[] arr, int k) {
    if (k == arr.length) {//排好了一种情况,递归的支路走到底了
      res.add(new String(arr));
    }

    //从k位开始的每个字符,都尝试放在新排列的k这个位置
    for (int i = k; i < arr.length; i++) {
      swap(arr, k, i);//把后面每个字符换到k位
      getPermutationCore(arr, k + 1);
      swap(arr, k, i);//回溯
    }
  }

  //交换位置
  static void swap(char[] arr, int i, int j) {
    char tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
  }

}

3.前缀法

思路图解

在这里插入图片描述连续扫描整个字符串,将没有出现的字符串添加到集合当中(先横后纵

代码实现

public class Demo19 {
  public static void main(String[] args) {
    String s = "123";
    permutation("", s.toCharArray());
  }

  final static int k = 3;
  static int count = 0;

  private static void permutation(String prefix, char[] arr) {
    if (prefix.length() == arr.length) {//前缀的长度==字符集的长度,一个排列就完成了
      // System.out.println(prefix);
      count++;
      if (count == k) {
        System.out.println("-------:" + prefix);
        System.exit(0);
      }
    }
    //每次都从头扫描,只要该字符可用,我们就附加到前缀后面,前缀变长了
    for (int i = 0; i < arr.length; i++) {
      char ch = arr[i];
      //这个字符可用:在pre中出现次数<在字符集中的出现次数
      if (count(prefix, ch) < count(arr, ch)) {
        permutation(prefix + ch, arr);
      }
    }
  }
  //计算ch字符在整个字符串中出现的次数
  private static int count(char[] arr, char ch) {
    int cnt = 0;
    for (char c : arr
        ) {
      if (c == ch) cnt++;
    }
    return cnt;
  }


  private static int count(String str, char ch) {
    int cnt = 0;
    for (int i = 0; i < str.length(); i++) {
      if (str.charAt(i) == ch) cnt++;
    }
    return cnt;
  }
}

4.递归法

4.1思路图解

在这里插入图片描述

思路与迭代法类似,迭代和递归可以互相转换

4.2代码实现

package LanQiao;
import java.util.Arrays;
 
public class Demo20{
//s表示,从array[start]后的数据进行全排列
public static void permute(char[] array,int start){  
    if(start==array.length){  // 输出
            System.out.println(Arrays.toString(array));
        }
    else
    for(int i=start;i<array.length;++i){
        swap(array,start,i);  //  交换元素
        permute(array,start+1);  //交换后,再进行全排列算法
        swap(array,start,i);  //还原成原来的数组,便于下一次的全排列
        }
}
 
private static void swap(char[] array,int s,int i){
    char t=array[s];
    array[s]=array[i];
    array[i]=t;
}
public static void main(String[] args){
       String s="ABC";
        permute(s.toCharArray(),0);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sparky*

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值