一、公式
n个元素全排列,有n!种排列方式。
即: f(n) = n!

二、实现思路及代码
思路一:头中尾插入法——单路递归
先对前n-1个字符全排列,得到全排列集合后,对集合中每个排列,第n个字符都可以往头插、往尾插、往中间插。
值得注意的是,往中间插的时候,是往该排列的每两个字符中间插,需遍历该排列。

/*** way01——插入法的迭代实现* @param str* @return*/public static ArrayList<String> getPermutation01(String str) {ArrayList<String> list = new ArrayList<>();
//        1、初始化,装入第一个字符list.add(str.charAt(0) + "");
//        2、把第2、3、4、、、n个字符插入到先前的序列集合中for (int i = 1; i < str.length(); i++) {ArrayList<String> temp = new ArrayList<>();char c = str.charAt(i);
//            每个字母可以插在每个集合元素的前中后for (String s : list) {temp.add(c + s);//字符加在此序列的前面temp.add(s + c);//加在后面for (int j = 1; j < s.length(); j++) {//加在中间:插入在每个字母后面(除最后一个)String tt = s.substring(0,j) + c + s.substring(j);temp.add(tt);}}list = temp;//更新list}return list;}
/*** way02——插入法的递归实现* @param str 要全排列的字符串* @param n 排列前n个字符,包括n  初始:str.length* @return*/public static ArrayList<String> getPermutation02(String str, int n) {ArrayList<String> list = new ArrayList<>();
//        1、出口if (n == 1) {list.add(str.charAt(0) + "");return list;}ArrayList<String> toList = getPermutation02(str,n-1);//取前包括一个字符前的的所有排列
//        2、把第n个元素分前中后插入前n-1个字符的每个排列for (String e : toList) {list.add(str.charAt(n-1) + e);//插前list.add(e + str.charAt(n-1));//插后for (int i = 1; i < e.length(); i++) {//插中,遍历插在每个字母的后面,除最后一个String tt = e.substring(0,i) + str.charAt(n-1) + e.substring(i);list.add(tt);}}return list;}

思路二:抽丝法——多路递归,Sn = ai + Sn-1 (0 <= i <= n-1)
遍历取出第i个字符,对剩余字符进行全排列得到全排列集合,遍历集合,把第i个字符插到每一个全排列头部。

 /*** way03——抽丝法* @param str* @return*/public static ArrayList<String> getPermutation03(String str) {ArrayList<String> list = new ArrayList<>();if (str.length() == 1) {list.add(str);return list;}char[] arr = str.toCharArray();//字符串》字符数组
//        遍历字符数组,轮流取出每一个字符for (int i = 0; i < arr.length; i++) {//            对剩余字符全排列String ss;if (i < arr.length-1) ss = str.substring(0,i) + str.substring(i+1);else ss = str.substring(0,i);ArrayList<String> temp = getPermutation03(ss);for (int j = 0; j < temp.size(); j++) {String tt = arr[i] + temp.get(j);list.add(tt);}}return list;}

思路三:交换法——多路递归 + 交换回溯[经典]
遍历取出第i个字符,每次都与第一个字符交换位置,再对剩余字符进行遍历,取出第j个与剩余字符的第一个位置进行交换。
交换后注意回溯。(因为这里是原址交换,大家共享一个串空间,牵一发而动全身。每次到交换到分支叶节点后得回溯到原状态)
即:对从k位开始的每一个字符,都尝试放在新排列后的第k位的位置上。(k从0开始)

/*** way04——交换法* @param str* @param k 从第k位开始的每个字符,都尝试放在第k位上 (k从0开始)* @return*/static ArrayList<String> li = new ArrayList<>();public static ArrayList<String> getPermutation04(String str,int k) {char[] arr = str.toCharArray();//字符串》字符数组getPermutation04Core(arr,0);return li;}public static void getPermutation04Core(char[] arr,int k) {if (k == arr.length) {//递归的一个支路走到底了,则说明一个全排列排好了li.add(new String(arr));}
//        从第k位开始的每个字符,都尝试放在第k位上for (int i = k; i < arr.length; i++) {swap(arr,i,k);//交换getPermutation04Core(arr,k+1);swap(arr,i,k);//回溯}}public static void swap(char[] A,int i,int j){char temp = A[i];A[i] = A[j];A[j] = temp;}

思路四:前缀法——可解决全排列字典序问题
核心:不断拼接前缀,直到长度=字符数组长度。
完整思路:把字符串转为字符数组,先对字符数组排序,遍历字符数组,依次取出每一个可用字符与前缀拼接作为新的前缀,
再从头遍历字符数组,依次把可用的字符与新的前缀进行拼接,作为更新的前缀……直到前缀长度=字符数组长度,一个全排列完成。
【注意】传进去的arr,需先排序。

 /*** way05——前缀法  字典序全排列问题* @param prefix* @param arr* @return*/static int count = 0;//统计出现了几个全排列public static void getPermutation05(String prefix,char[] arr) {//        前缀长度==arr长度,说明一个全排列完成if (prefix.length() == arr.length) {//            System.out.println(prefix);count++;}
//        遍历字符数组,轮流取出可用字符,加到前缀后面,作为新的前缀递归下去for (int i = 0; i < arr.length; i++) {//            判断当前字符是否可用——该字符在前缀中出现次数<字符数组中出现次数if (countCharTimes(prefix.toCharArray(),arr[i]) < countCharTimes(arr,arr[i])) {//                prefix = prefix + arr[i];//ERROR: 不能拼接!!!,会改变前缀,影响后续循环getPermutation05(prefix + arr[i],arr);}}}/*** 统计在arr数组中字符c出现的次数* @param arr* @param c* @return*/public static int countCharTimes(char[] arr,char c) {int times = 0;for (int i = 0; i < arr.length; i++) {if (arr[i] == c) times++;}return times;}

例题:leetCode60 n个数的数列组合照出字典序的第k个排列

比较:
A、空间:插入法、抽私法都需要开辟额外ArrayList来存储子排列;交换法不需要额外的ArrayList,直接在数组上交换排列,节省空间;
B、时间:交换法<插入法<抽丝法
C、交换法和前缀法的比较:
交换法代码简洁,自然去重,但无法维持字典序。
前缀法代码较多,手动去重,能维持字典序。
使用场景:
A、若只需要求全排列——交换法(优)
B、若全排列要求字典序——前缀法

三、遇到的问题——堆溢出
堆溢出:
java.lang.OutOfMemoryError: Java heap space:
内存溢出java.lang.OutOfMemoryErrory后面一般会跟上内存溢出的区域。
PermGen space(方法区), heap space(堆内存)
解决方法:
1、如果是PermGen space方法区内存溢出,可尝试加大MaxPermSize
2、如果是heap space 堆内存溢出,可尝试修改Xmx
-Xms
设置JVM初始化堆内存大小
-Xmx
设置JVM最大的堆内存大小

【算法】全排列的四种思路相关推荐

  1. 基本的排序算法php,php四种基础排序算法

    原标题:php四种基础排序算法 曾经有网友问我关于面试题的问题,今天就发一个面试题笔试经常会出的排序算法,大家可以参考一下,如有问题可以给我留言. /** * php四种基础排序算法的运行时间比较 * ...

  2. python 聚类_聚类算法中的四种距离及其python实现

    欧氏距离 欧式距离也就是欧几里得距离,是最常见也是最简单的一种距离,再n维空间下的公式为: 在python中,可以运用scipy.spatial.distance中的pdist方法来实现,但需要调整其 ...

  3. 计算机故障维修四种思路,维修“望闻问切” 电脑故障的排除方法

    看到这个题目,很多读者可能会感到奇怪,中医与计算机维修风马牛不相及,它们怎么会扯到一起呢?我们知道,中医在长期的医疗实践中,总结出了四种论断疾病的方法,这就是"望.闻.问.切"四诊 ...

  4. 计算机故障维修四种思路,计算机常见问题维修小技巧

    计算机 日常生活里我们已经离不开计算机,我经常可以看见家家户户都有计算机,无论是台式还是笔记本.可是当新买来不久的或者用了一段时间的电脑,出现故障,我们应该怎么去应对. 也许会出现以下场景.场景一:你 ...

  5. 【常用算法总结——最短路径四种方法】

    以下转自https://blog.csdn.net/weixin_42060896/article/details/82216379 例题:HDU 2544 最短路 Time Limit: 5000/ ...

  6. 根号类算法讲解——各(四)种莫队(填坑)

    这个坑终于填了- 上文接这里 莫队算法 这就是莫队(确信) 先放个可离线的题: 可离线:给你个序列,m次询问(可离线)一段区间有多少个不同的数(可离线)(数据范围 105 10 5 10^5)可离线 ...

  7. 求解最大公约数算法(包含四种方法)

    方法一: #include<iostream> #include<algorithm> #include<cstdio> #include<cmath> ...

  8. 快速排序 python 4种写法_[算法] 关于快速排序的四种写法

    前序 说到排序算法,应该算是家喻户晓,人人皆知的大路货了.但是往往这些为人所熟知的东西中,也存在一些可以令人琢磨的细节. 这不,某天深夜,无所事事,大概是太寂寞,在思念了一番妹子以后,脑子里突然闪过了 ...

  9. 求解最大流的四种算法介绍、利用最大流模型解题入门

    求解最大流的四种算法介绍.利用最大流模型解题入门 上一篇中介绍了网络流的基础,最大流最小割定理的证明,下面来看如何求一个容量网络的最大流,这里介绍四种算法:EK算法.SAP算法.DINIC算法.HLP ...

最新文章

  1. hub-spock-ospf,nbma
  2. 解决查看框架源码时 class file editor source not found
  3. matlab在图像调用Gabor滤波
  4. mycat 启动失败 The specified size exceeds the maximum representable size JVM exited while loading the a
  5. linux 密码策略设置,设置Linux密码策略
  6. linux--GD库安装
  7. 用Cocos2dx开发棋牌游戏的观点解析
  8. 课时67.标签选择器(掌握)
  9. 保守官僚 诺基亚就这样迷失在智能机时代?
  10. c# out原理 ref_移植贪吃蛇——从C#到C++
  11. [转载] 5.2 calendar--通用日期的相关函数(4)
  12. 洛谷P2473奖励关——状压DP
  13. jmeter笔记02
  14. 181221每日一句
  15. 从零开始配置 vim(3)—— 键盘映射进阶
  16. 2021年全球无损检测设备收入大约2189.6百万美元,预计2028年达到3076.2百万美元,2022至2028期间,年复合增长率CAGR为5.4%
  17. 常见文件扩展名和它们的说明(转)
  18. Skype for Business Server前端高可用原理分析
  19. QX2601液晶手写板擦写板专用IC芯片
  20. PHP数据加密的几种方式

热门文章

  1. Maven-3.maven知识点
  2. Matlab使用xlsread读入xlsx文件错误处理
  3. 大数据分析工程师面试集锦5--Spark面试指南
  4. 哪个牌子的儿童护眼灯好?分享315护眼灯合格名单的护眼台灯
  5. 企业上市需要哪些条件
  6. 项目经验--听讲座有感
  7. hadoop HA 架构
  8. 按键精灵-离线打包 免会员 免登录版 打包工具
  9. Spark RDD 持久化
  10. Web渗透攻击之vega