求全排列的两种方法(Java)

2023-10-28 02:30
文章标签 java 方法 两种 排列 求全

本文主要是介绍求全排列的两种方法(Java),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

递归法

假设我们有0,1,2,3四个数需要全排列,递归法是一种比较类似于深度搜索的方法,直到递归最深处,才得出结果。

其大概思路是,设置一个游标start,游标所到之处,其左侧已经考虑过,利用递归思想求剩下的全排列。

仔细分析,依次考虑每一位数。由于对于每一位数,它可能的数包括除了之前考虑过的所有数,因此将start右侧(包括start)的所有数都和start这一位交换一次,每交换后,马上进入递归函数(start+1),接着再执行一次原交换,用于复原。这样就做成了把每一个数都在这个位上排列一次,递归函数的调用表示对剩下的数进行全排列。

代码如下:

package main;public class Main {static int[] a = {0, 1, 2, 3};static int result = 0;public static void main(String[] args) {dfs(0);System.out.println("The total of all permutation of a[] is: " + result);}public static void dfs(int start) {if (start >= a.length) {System.out.print(a[0]);for (int i = 1; i < a.length; i++) {System.out.print(", " + a[i]);}System.out.println();result++;return;}for (int i = start; i < a.length; i++) {swap(start, i);dfs(start + 1);swap(start, i);}}public static void swap(int i, int j) {int temp = a[i];a[i] = a[j];a[j] = temp;}
}

给出输出结果:
在这里插入图片描述

回溯法

这种方法叫回溯法,他的思想也是用到递归的思想,长得也和上面递归法很像,只是从递归函数的解读来说,和递归法还是有区别的。(leetcode上经常有回溯法求解的题)

在回溯法中,通常有多个辅助变量:待选列表或集合,已选列表或集合,表示结果的列表或集合,等等。其递归思想,就是

  1. 每次遍历待选
  2. 更新表示结果的列表或集合
  3. 更新已选列表或集合
  4. 执行递归操作
  5. 恢复表示结果的列表或集合,恢复已选列表或集合。

这么看来,好像是和递归法没什么区别。我的理解是,递归法和回溯法本质上都是递归,在求全排列问题上,递归解法和回溯法极其相似,但是在一些应用问题中,用递归法不是那么好理解,而回溯法的思考模式和我们人想问题差不多,递归套路就是挨个试,因此回溯法还是比较容易接受的。

还有一点要注意的是,在全排列问题上,回溯法用的复杂度较高,效率低于递归法。

下面附上代码:

package main;import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;public class Main {static int[] a = {0, 1, 2, 3};static Set<Integer> all = new HashSet<Integer>(); // 全体集合(待选集合=全体集合-已选集合)static Set<Integer> used = new HashSet<Integer>(); // 已选集合static List<List<Integer>> resultList = new ArrayList<>(); // 全局结果列表public static void main(String[] args) {for (int i = 0; i < a.length; i++) {all.add(a[i]);}backtrack(0, new ArrayList<Integer>());System.out.println("The total of all permutation of a[] is: " + resultList.size());}public static void backtrack(int p, List<Integer> tempresult) {if (p >= a.length) {System.out.print(tempresult.get(0));for (int i = 1; i < tempresult.size(); i++) {System.out.print(", " + tempresult.get(i));}System.out.println();resultList.add(tempresult);return;}for (Integer n : all) {if (!used.contains(n)) {used.add(n);tempresult.add(n);backtrack(p + 1, tempresult);tempresult.remove(tempresult.size() - 1);used.remove(n);}}}public static void swap(int i, int j) {int temp = a[i];a[i] = a[j];a[j] = temp;}
}

执行结果:
在这里插入图片描述

执行结果对比

比较上面两个方法中,输出执行结果的区别,发现:

在递归法中:
在这里插入图片描述
回溯法中:
在这里插入图片描述
由于两种方法(尽管都用到了递归)对递归含义的解释,也就是执行思路不同,导致了结果输出顺序的不同。

在递归法中,先输出0321,后输出0312,是因为此时正在考虑第二位(start=1),已经对这一位考虑过了数字1和数字2,现在需要将数字3和原本的1做交换,而这个操作和数字2无关,所以数字2还在它原来的位置上。直到考虑第三位时(start=2),才与后面的1交换,输出了0321.

在回溯法中,先输出0312,后输出0321,这是因为,在集合的遍历中,由于对集合all的遍历顺序实际上是字典序(数字从小到大),因此这就好比我们人的思维模式,逐位考虑可能的数字,而考虑的顺序就是字典序了。这样最后输出的全排列顺序,也是字典序。

谢谢!

这篇关于求全排列的两种方法(Java)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/290070

相关文章

Spring @Scheduled注解及工作原理

《Spring@Scheduled注解及工作原理》Spring的@Scheduled注解用于标记定时任务,无需额外库,需配置@EnableScheduling,设置fixedRate、fixedDe... 目录1.@Scheduled注解定义2.配置 @Scheduled2.1 开启定时任务支持2.2 创建

SpringBoot中使用Flux实现流式返回的方法小结

《SpringBoot中使用Flux实现流式返回的方法小结》文章介绍流式返回(StreamingResponse)在SpringBoot中通过Flux实现,优势包括提升用户体验、降低内存消耗、支持长连... 目录背景流式返回的核心概念与优势1. 提升用户体验2. 降低内存消耗3. 支持长连接与实时通信在Sp

Conda虚拟环境的复制和迁移的四种方法实现

《Conda虚拟环境的复制和迁移的四种方法实现》本文主要介绍了Conda虚拟环境的复制和迁移的四种方法实现,包括requirements.txt,environment.yml,conda-pack,... 目录在本机复制Conda虚拟环境相同操作系统之间复制环境方法一:requirements.txt方法

Nginx 重写与重定向配置方法

《Nginx重写与重定向配置方法》Nginx重写与重定向区别:重写修改路径(客户端无感知),重定向跳转新URL(客户端感知),try_files检查文件/目录存在性,return301直接返回永久重... 目录一.try_files指令二.return指令三.rewrite指令区分重写与重定向重写: 请求

MySQL 打开binlog日志的方法及注意事项

《MySQL打开binlog日志的方法及注意事项》本文给大家介绍MySQL打开binlog日志的方法及注意事项,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 目录一、默认状态二、如何检查 binlog 状态三、如何开启 binlog3.1 临时开启(重启后失效)

Spring Boot 实现 IP 限流的原理、实践与利弊解析

《SpringBoot实现IP限流的原理、实践与利弊解析》在SpringBoot中实现IP限流是一种简单而有效的方式来保障系统的稳定性和可用性,本文给大家介绍SpringBoot实现IP限... 目录一、引言二、IP 限流原理2.1 令牌桶算法2.2 漏桶算法三、使用场景3.1 防止恶意攻击3.2 控制资源

Mac系统下卸载JAVA和JDK的步骤

《Mac系统下卸载JAVA和JDK的步骤》JDK是Java语言的软件开发工具包,它提供了开发和运行Java应用程序所需的工具、库和资源,:本文主要介绍Mac系统下卸载JAVA和JDK的相关资料,需... 目录1. 卸载系统自带的 Java 版本检查当前 Java 版本通过命令卸载系统 Java2. 卸载自定

springboot下载接口限速功能实现

《springboot下载接口限速功能实现》通过Redis统计并发数动态调整每个用户带宽,核心逻辑为每秒读取并发送限定数据量,防止单用户占用过多资源,确保整体下载均衡且高效,本文给大家介绍spring... 目录 一、整体目标 二、涉及的主要类/方法✅ 三、核心流程图解(简化) 四、关键代码详解1️⃣ 设置

Java Spring ApplicationEvent 代码示例解析

《JavaSpringApplicationEvent代码示例解析》本文解析了Spring事件机制,涵盖核心概念(发布-订阅/观察者模式)、代码实现(事件定义、发布、监听)及高级应用(异步处理、... 目录一、Spring 事件机制核心概念1. 事件驱动架构模型2. 核心组件二、代码示例解析1. 事件定义

SpringMVC高效获取JavaBean对象指南

《SpringMVC高效获取JavaBean对象指南》SpringMVC通过数据绑定自动将请求参数映射到JavaBean,支持表单、URL及JSON数据,需用@ModelAttribute、@Requ... 目录Spring MVC 获取 JavaBean 对象指南核心机制:数据绑定实现步骤1. 定义 Ja