全排列算法

article/2025/10/14 9:14:51

全排列的概念

排列

从n个数中选取m(m<=n)个数按照一定的顺序进行排成一个列,叫作从n个元素中取m个元素的一个排列。不同的顺序是一个不同的排列。从n个元素中取m个元素的所有排列的个数,称为排列数(几种排法)。

全排列

从n个元素取出n个元素的一个排列,称为一个全排列。全排列的排列数公式为 n!

时间复杂度

n个数的全排列有n!种,每一个排列都有n个数据,所以输出的时间复杂度为O(n*n!),呈指数级,无法处理大型数据。

一、逐步生成大法——迭代(递推)法

三层for循环

第一层:从第二个字符开始遍历

第二层:访问上一趟集合数组中的每一个字符串,然后给每个字符串前面、后面插入字符

第三层:往字符串中间插入字符

需要额外集合

import java.util.ArrayList;
import java.util.Scanner;public class Main {public static void main(String[] args) {String s = "abc";ArrayList<String> res = getPermutation(s);System.out.println(res);}public static ArrayList<String> getPermutation(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> new_res = new ArrayList<>();//创建临时集合,用来存储新生成的字符串for(String str:res){//遍历上一趟迭代结果集合中的每一个字符串String newStr = c + str;//插入前面new_res.add(newStr);newStr = str + c;//插入后面new_res.add(newStr);for(int j=1;j<str.length();j++){newStr = str.substring(0,j) + c + str.substring(j);//插入中间new_res.add(newStr);}}res = new_res;//本次迭代结果作为下一次迭代初始值}return res;//返回最后结果}
}

二、递归

跟上面的递推有一点像,需要额外集合

import java.util.ArrayList;
import java.util.Scanner;public class Main {public static void main(String[] args) {String s = "abc";int n = s.length();ArrayList<String> res = getPermutation(s, n);System.out.println(res);}public static ArrayList<String> getPermutation(String s, int n) {ArrayList<String> res = new ArrayList<>();//创建集合,用来存储第一个元素,用于递归终止if (n == 1) {//递归终止条件res.add(s.charAt(0) + "");//初始化,把a添加进去return res;//返回初始集合} else {ArrayList<String> res1 = getPermutation(s, n - 1);//创建集合,用于存储上一趟迭代的结果,为了不重复本地变量,命名为res1,代替reschar c = s.charAt(n - 1);ArrayList<String> new_res = new ArrayList<>();//创建临时集合,用于存储新生成的字符串for (String str : res1) {String newStr = c + str;//加前new_res.add(newStr);newStr = str + c;//加后new_res.add(newStr);for (int j = 1; j < str.length(); j++) {//加中间newStr = str.substring(0, j) + c + str.substring(j);new_res.add(newStr);}}res1 = new_res;//更新res1,把迭代结果赋值给res1return res1;//返回迭代结果}}
}

三、回溯法(或交换法)不在乎顺序的情况下,只求全排列

特点:代码简洁、处理重复(字符)自然、非字典序(,如果需要字典序则在最后对字符串集合进行一次排序 Collections.sort( ) )、不需要额外集合(因为是对同一个数组空间操作)

三个思维难点:

  1. 在for循环内进行多路(多分支)递归,递归先执行完毕
  2. 先纵后横
  3. 需要回溯,恢复至最初状态,abc,因为共享存储空间,每次都是对同一个数组进行修改,每次都要从根节点abc开始向下层逐层递归

画图理解:

程序大致流程:比如第一支分路,先确定 a 从 a 开始,往下递归,再依次确定 b 和 c ,到达边界条件,把当前数组情况 abc,存入集合。再回溯,恢复交换前的状态(abc),因为 k=1 时,for循环还未执行完,进行第二轮,交换 b、c位置,确定了 c ,往下递归,k=2 时,确定了 b ,到达边界条件,把当前数组情况 acb 存入集合,再次逐层回溯,直到恢复初始 abc ,再进行第二路分支......

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;public class Main {public static void main(String[] args) {String s = "abc";ArrayList<String> res = new Main().getPermutation(s);//赋值给resSystem.out.println(res);}ArrayList<String> res = new ArrayList<>();// 创建集合public ArrayList<String> getPermutation(String q) {char[] c = q.toCharArray();Arrays.sort(c);getPermutationCore(c, 0);// 调用核心递归方法求解//Collections.sort(res);//对集合进行排序,字典序return res;// 集合}private void getPermutationCore(char[] c, int k) {// 核心递归方法if (k == c.length) {// 完成一种排列情况,存入集合res.add(new String(c));}for (int i = k; i < c.length; i++) {swap(c, k, i);// 交换getPermutationCore(c, k + 1);// 递归至下一层swap(c, k, i);//在回溯到上一层之前,给换回来,到最顶层时恢复成abc7  }}static void swap(char[] c, int i, int j) {// 交换字符元素char temp = c[i];c[i] = c[j];c[j] = temp;}
}

不排序,输出结果为:

[abc, acb, bac, bca, cba, cab]

排序,按照字典序,输出结果为:

[abc, acb, bac, bca, cab, cba]

四、前缀法 求第k个排列

特点:复杂(代码量多)、处理重复(字符)较差(需要进行判断)、字典序(处理较好,每次加的是字符集中未加入字符字典序最小的那个字符)

对于求第k个排列来说,可以使用交换法求出所有的排列,然后对所有排列进行排序,从而解出第k个排列,但是这样的做法不节省时间和空间,没效率。实际上可以按序求出排列,直到求出第k个排列,然后返回就行了。

大致流程:从头开始扫描字符集abc,(把字符加入前缀中之前先判断是否已经加入过)把a加入前缀,直到完成一中排列abc,直到退回上上层ab,此时循环未执行完,进入下一轮循环,把c加入进来,变成ac......

需要额外处理重复的字符

 

import java.util.ArrayList;
import java.util.Arrays;public class Main {public static void main(String[] args) {String s = "123";getPermutation("", s.toCharArray());}final static int k = 3;// 第k个排列static int count = 0;// 记录排列完成次数private static void getPermutation(String prefix, char[] arr) {if (prefix.length() == arr.length) {// 边界条件:前缀的长度==字符集的长度,一个排列就完成了count++;if (count == k) {// 程序结束条件System.out.println(prefix);// 输出目标排列System.exit(0);// 正常退出,结束当前正在运行的java虚拟机}}// 每次都从头扫描字符集,只要该字符可用(可添加),我们就附加到前缀后面,前缀变长了for (int i = 0; i < arr.length; i++) {char ch = arr[i];// 处理重复字符。这个字符可用:在prefix中出现的次数 < 在字符集中出现的次数if (count(prefix, ch) < count(arr, ch)) {getPermutation(prefix + ch, arr);// 把字符加入前缀,进行递归}}}private static int count(String prefix, char ch) {// 计算当前字符在前缀prefix中出现的次数int cnt = 0;for (int i = 0; i < prefix.length(); i++) {if (prefix.charAt(i) == ch) {cnt++;}}return cnt;}private static int count(char[] arr, char ch) {// 计算当前字符在字符集中出现的次数int cnt = 0;for (int i = 0; i < arr.length; i++) {if (arr[i] == ch) {cnt++;}}return cnt;}
}

输出:213


http://chatgpt.dhexx.cn/article/txyEth4m.shtml

相关文章

激活JRebel

生成新的 GUID 将生成的GUID 粘贴到此处 https://jrebel.qekang.com/ 如&#xff1a; https://jrebel.qekang.com/cf0c9d95-c31f-4e75-bc5a-146291b8bb71

JRebelXRebel的配置和使用(进阶篇)

JRebel&XRebel的配置和使用 嘚吧嘚设置JRebel快捷键XRebel使用 嘚吧嘚 之前简单介绍了JRebel&XRebel的安装和使用&#xff0c;不了解的朋友可以补补课哈&#x1f606;。 JRebel&XRebel这款插件不仅仅可以用来热部署&#xff0c;所以继续分享一下这款插件的相关使…

IDEA热部署JRebel插件激活教程

JRebel简介 JRebel是一款实现热部署的开发工具&#xff0c;它可以允许你在启动程序时修改java代码直接进行编译生效&#xff0c;无须手动重启。热部署的实现会为你节省了大量重启时间&#xff0c;明显提高个人开发效率。 安装JReable 同其它插件安装一样&#xff0c;请按照以…

Idea热部署插件JRebel+XRebel

1、下载地址&#xff1a;https://plugins.jetbrains.com/plugin/4441-jrebel-and-xrebel/versions 保险起见这里建议下载2022.4.1版本&#xff0c;否则容易出现JRebel LS client not configured的问题&#xff0c;如果你已经出现了&#xff0c;可以参考 https://blog.csdn.ne…

JRebel 热部署

前言 Jrebel 可快速实现热部署&#xff0c;节省了大量重启时间&#xff0c;提高了个人开发效率。 IDEA上原生是不支持热部署的&#xff0c;一般更新了 Java 文件后要手动重启 Tomcat 服务器&#xff0c;才能生效&#xff0c;浪费时间浪费生命&#xff0c;目前对于idea热部署最…

IDEA热部署插件JRebel使用

JRebel安装与激活 JRebel 使用 此时已经安装好并已激活&#xff0c;我们使用 JRebel debug的时候&#xff0c;修改代码&#xff0c;不能实现热部署&#xff0c;因此还需要设置其他地方 1.项目自动编译 设置 compiler.automake.allow.when.app.running ctrlshiftA 或者 help->…

IDEA插件-热部署:JRebel

一、摘要 springboot项目开发过程中通常修改了某分部代码需要重启服务才能生效。通过JRebel插件可以实现热部署&#xff0c;避免了频繁重启服务。 JRebel是一套JavaEE开发工具。 Jrebel 可快速实现热部署&#xff0c;节省了大量重启时间&#xff0c;提高了个人开发效率。 二、…

Jrebel安装使用教程 及 Jrebel 4.2版本激活失效的处理(超简洁明了)

写在前面&#xff1a;不小心更新了Jrebel插件导致插件用不了qwq&#xff0c;经过查阅多方面的资料总结出了解决这个问题的方法&#xff0c;现分享给大家~ &#xff08;如果原本没安装JRebel插件请直接从第三步开始看~&#xff09; 第一步&#xff1a;删除4.2版本 先在Plugins…

JRebel插件热部署快速入门教程

文章目录 引入插件安装插件激活打开激活窗口激活插件 插件使用设置项目热更新热更新说明演示热更新 引入 视频讲解JRebel安装、使用、部署 Jrebel能够非常方便的帮助我们进行项目的热更新&#xff0c;尤其是前端也嵌在后端工程中的单体项目&#xff0c;热更新能减少一半的开发…

JRebel插件使用详解

JRebel插件安装与使用图文教程 JRebel是一款JVM插件&#xff0c;它使得Java代码修改后不用重启系统&#xff0c;立即生效。IDEA上原生是不支持热部署的&#xff0c;一般更新了 Java 文件后要手动重启 Tomcat 服务器&#xff0c;才能生效&#xff0c;浪费时间浪费生命。 目前对…

javaweb开发,提高效率利器——JRebel

JRebel用了有一段时间了&#xff0c;发现确实好用&#xff0c;节省了很多不必要的时间&#xff0c;提高了开发效率。在这里记录一下他的安装和使用过程&#xff0c;希望能帮助到有需要的人。 官网&#xff1a;https://www.jrebel.com/ 一、JRebel简介 jrebel是国外公司perfo…

JRebel 和 XRebel 激活

1&#xff1a;JRebel 和 XRebel的作用 JRebel&#xff1a;修改完代码&#xff0c;不想重启服务&#xff0c;就使想代码生效。 XRebel&#xff1a;请求中&#xff0c;各个部分代码性能监控。例如&#xff1a;方法执行时间&#xff0c;出现的异常&#xff0c;SQL执行时间&#x…

JRebel安装、最新激活方式

安装JRebel 1、在IDEA中一次点击 File->Settings->Plugins->Brows Repositories 2、在搜索框中输入JRebel进行搜索 3、找到JRebel for intellij 4、install 5、安装好之后需要restart IDEA 激活JRebel 生成 GUID 的网址 https://www.guidgen.com/用这个网址 生成的…

Jrebel激活

一般一个产品的生命周期就像一个抛物线。JRebel 亦是如此。 做 Java 开发&#xff0c;离不开热发布、热部署。JRebel 就是一套 JavaEE 开发工具 JRebel 可快速实现热部署&#xff0c;节省了大量重启时间&#xff0c;提高了个人开发效率。 JRebel 是一款 JAVA 虚拟机插件&…

idea使用JRebel插件详解

简介 JRebel是一套JavaEE开发工具。 Jrebel 可快速实现热部署&#xff0c;节省了大量重启时间&#xff0c;提高了个人开发效率。 JRebel是一款JAVA虚拟机插件&#xff0c;它使得JAVA程序员能在不进行重部署的情况下&#xff0c;即时看到代码的改变对一个应用程序带来的影响。JR…

Idea之热部署插件JRebel+XRebel

文章目录 Idea之热部署插件JRebelXRebel1. devtools热部署1. 使用流程2. 缺点 2. Jrebel and XRebel for IntelliJ1. 安装2. 激活JRebel-方式一3. 激活JRebel方式二4. 使用JRebel5. 使用XRebel Idea之热部署插件JRebelXRebel 热部署&#xff1a;就是在修改代码之后&#xff0c…

JRebel 热部署插件的安装使用

文章目录 Jrebel简介JRebel的安装和使用idea安装JRebelJRebel的使用 JRebel的Activation Jrebel简介 当你修改doGet&#xff0c;doPost等一些内容时&#xff0c;你再次访问&#xff0c;访问到的内容不变&#xff0c;除非重启或重新加载class文件。   用Jrebel 可快速实现热部…

idea之热部署插件jrebel的使用

背景 一个java web项目&#xff0c;在写的过程中我们需要不断调试&#xff0c;如果没有热部署&#xff0c;则我们每修改一次项目要重启一次&#xff0c;验证问题有没有得到解决。如果项目很小&#xff0c;启动只要几秒或十几秒&#xff0c;可能感觉影响不是很大&#xff1b;但当…

2023idea中热部署插件JRebel的激活方式

Rebel介绍# JRebel是一款JVM插件&#xff0c;它使得Java代码修改后不用重启系统&#xff0c;立即生效。IDEA上原生是不支持热部署的&#xff0c;一般更新了 Java 文件后要手动重启 Tomcat 服务器&#xff0c;修改才能生效&#xff1b;所以推荐使用 JRebel 插件进行热部署。 JRe…

JRebel激活教程

1.在idea的plugins中搜索jrebel进行安装插件 2.重启idea 3.激活jrebel 下载代理地址 Release v1.4 ilanyu/ReverseProxy GitHub 双击下载的exe文件 在idea中找到激活界面 激活需要生成uuid&#xff0c;下面是uuid的生成网站 Online UUID Generator Tool 最后把JRebel设…