经典算法之——解决全排列问题以及详解_排列问题的过程-程序员宅基地

技术标签: 算法  深度优先  java  图论  


全排列解析

1.这里就举例array={1,2,3,4,5}的全排列;首先根据字典的排序以小到大,将整个问题分解为子集合解决(整个感觉有点像树的结果,根分到叶子),我们现在要先固定第一位,然后变成了array1={2,3,4,5}的全排列,然后就一直进行分解直到array2={3,4,5}(固定前两位),array3={4,5}(固定前三位),array4={5}(固定前四位),到这时这里的第一次全排列,就分解到只有一个数的子集合,就算一种情况;
2.接下来就返回到上一种情况,也就是array3的子集合,因为刚刚只是排了最后一个子集合(array4),所以array3子集合就要变成{5,4},这里算一种,到这里array3的所有可能已经完了,再接下来会回到上一个集合array2的可能{3,4,5},{3,5,4}都已经排过了,所以3开头就不能要了,就会变成array2={ 4,3,5},再把这个array2进行分解子集合再排,然后就是一直延续下去,排完整个大的集合。

这里就只介绍这几种方法:
1.回溯法
2. 字典序法
3. 邻位对换法

一、回溯法

“回溯”指的是“状态重置”,可以理解为“恢复现场”,是在编码的过程中,是为了节约空间而使用的,而在递归或者深度优先中根据需要的场合来配合回溯法可以进一步对自己的代码进行优化。

大概就是一个树形的结构

回溯的基本模板

#include<iostream>
#include<algorithm>
using namespace std;
const int N=10;
bool st[N];//用来判断1~n这n个数是否被选。true代表已经被选了,false反之
int p[N];//用来记录1~n个位置选的是哪个数
int n;
void dfs(int u){
    
    if(u>n){
    //当n个位置都确定之后就打印
        for(int i=1;i<=n;i++){
    
            cout<<p[i]<<" ";
        }
        cout<<endl;
        return;
    }
    for(int i=1;i<=n;i++){
    //第u个位置开始选数
        if(!st[i]){
    //如果这个数没有被选
            st[i]=true;//选择这个数打上标记
            p[u]=i;//记录
            dfs(u+1);//开始枚举下一个位置
            st[i]=false;//恢复现场
        }
    }
}
int main()
{
    
    cin>>n;
    dfs(1);//从第一个位置开始遍历
    return 0;
}

二、字典序法

首先字典序法在数学中就是字典或词典顺序(也称为词汇顺序,字典顺序,字母顺序或词典顺序)是基于字母顺序排列的单词按字母顺序排列的方法
这也就是前面所解释说明的那样,以数组 [1, 2, 3] 的全排列为例。

以 1 开头的全排列为[1, 2, 3], [1, 3, 2];
以 2 开头的全排列为[2, 1, 3], [2, 3, 1];
最后以 3 开头的全排列为[3, 1, 2], [3, 2, 1];
从上面的全排列可以看出来,开头固定数是从左往右依次增大的,对这就是字典序法

这里找了一张图
在这里插入图片描述

代码如下(示例):

/**
list就是集合R
k 表示list中的开始位置
m 表示list中的结束位置
*/
	static int[] list={
    1,2,3};
	public static void main(String[] args) {
    
	 perm(list, 0, list.length-1);
	}
	 public static void perm(int[] list,int k,int m){
    
	     //产生list中第k到m位置上元素的全排列
		if(k==m){
    //只剩一个元素的情况下的全排列,也是递归出口
			for(int i=0; i<=m; i++){
    
				System.out.print(list[i]);
			}
			System.out.println();
            return;
		}else{
    
			for(int i=k; i<=m; i++){
           
				swap(list,k,i);//将第i个元素和该子序列中的第一个元素进行交换
				perm(list,k+1,m);//求解规模为n-1的子问题
				swap(list,k,i);//将它换回
			}
		}
	}
	public static void swap(int[] list,int k,int i){
     //进行交换
		int temp = list[k];
		list[k] = list[i];
		list[i] = temp;
	}

三、相邻对换法

邻位对换法是全排列生成算法中的其中一种,它的换位是双向的,通过保存数字的“方向性”来快速得到下一个排列

说明:
1、 每个数有一个移动方向,向左或向右。如果数x的移动方向上最靠近它的数比它要小,那么x是可移动的。初始时序列为{1, 2, 3, …, n-1, n},方向都为向左。
2、 移动最大数n,直到不能移动为止,每改变一次位置输出一个序列(此时n在最左边或最右边)。
3、 找当前可移动的最大数m。若能找到,移动m,把所有比m大的数的方向置反,返回第2步;若不能找到,算法停止。

以array={1,2,3,4}的全排列为举例,当我们其中子集合{1,2,3}的全排列为:

123 132 312
321 231 213

这6个数,那么将4排入其中,则过程为这样
在这里插入图片描述

代码部分

import java.util.ArrayList;

public class Permutation {
    

    public static void main( String[] args ) {
    
        String[] result = permutation( "12345" );
        // System.out.println( result.length + "\r\n" );
        for ( String s : result ) {
    
            System.out.println( s );
        }
    }

    public static String[] permutation( String str ) {
    

        ArrayList<String> charList = new ArrayList<String>();
                char[] arrChars = str.toCharArray();
                long  times= 1;
                int  k= arrChars.length - 2;
                0int  inc= -1;

        for ( int i = 1; i < arrChars.length + 1; i++ ) {
    
            times *= i;
        }

        for ( int i = 1; i < times; i++ ) {
    

            swap( arrChars, k, k + 1 );
            charList.add( new String( arrChars ) );
            k += inc;

            if ( k == -1 ) {
    
                inc = 1;
                k = 0;
                swap( arrChars, arrChars.length - 2, arrChars.length - 1 );
                charList.add( new String( arrChars ) );
                i++;
            }

            if ( k == arrChars.length - 1 ) {
    
                inc = -1;
                k = arrChars.length - 2;
                swap( arrChars, 0, 1 );
                charList.add( new String( arrChars ) );
                i++;
            }
        }

        return charList.toArray( new String[0] );
    }

    private static void swap( char[] arr, int k1, int k2 ) {
    
        char tmp = arr[k1];
        arr[k1] = arr[k2];
        arr[k2] = tmp;
    }
}

在排列组合中,有几个重要的数学公式: 在这里插入图片描述
在这里插入图片描述

全排列问题大概到这里,后续有什么补充的我再添加

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/m0_68987535/article/details/130755725

智能推荐

android原生!史上最全的Android面试题集锦,快来收藏!_安卓面试题-程序员宅基地

文章浏览阅读337次。开头在大厂,写得一手好文档是一个非常吃香的技能。这可不只是一个锦上添花的东西,而是很多工程师晋升,打造自己话语权的武器。 我这两年在组内的深刻体会就是,大部分厉害的高级工程师(不包括那些纯混日子靠资历晋升的人),写文档的能力一点也不含糊,很能抓住上级和项目的G点。可能有人会觉得,我技术牛逼就行了,为啥还要提高写文档的能力,有这功夫我还不如多看看源码分析?这是一些初级或者刚入门的工程师的普遍的困惑。这是因为大部分刚刚入行的朋友有一个很深的误区,就是他们以为做软件工程是一个和计算机打交道的工作,其实不然。_安卓面试题

C# 之 WPF 统计图表开发方案_c# wpflivechart-程序员宅基地

文章浏览阅读9.2k次,点赞8次,收藏72次。C# 之 WPF 统计图表开发文档一、前言二、环境配置1、开发环境2、加载 LiveCharts 库3、添加必须的头文件三、基础图形1、柱状图一、前言本项目的统计图使用LiveCharts 控件集成。LiveCharts, 官网:https://lvcharts.net 是一款简单,灵活,交互式和强大的 DOTNET数据可视化图表控件,内置多种统计图表,可满足本项目的需求。二、环境配置..._c# wpflivechart

DBeaver 快捷键大全_dbeaver快捷键-程序员宅基地

文章浏览阅读5k次,点赞7次,收藏23次。有些快捷键未经验证,如有问题望不吝指正!ctrl + enter 执行sqlctrl + \ 执行sql,保留之前窗口结果ctrl + alt + ↑ 向上复制一行ctrl + alt + ↓ 向下复制一行ctrl + shift + F 对sql语句进行格式化,对于很长的sql语句很有用ctrl + d 删除当前行alt + ↑ 向上选定一条sql语句alt + ↓ 向下选定一条sql语句ctrl + / 行注释ctrl + shift+ / 块注释ctrl + f 查找、替换_dbeaver快捷键

【基础】WebView浏览器组件-程序员宅基地

文章浏览阅读5.4k次。ad_webview

CentOS上面安装Oracle 11GR2_oracle11.2.0需下载什么版本的export-程序员宅基地

文章浏览阅读1.7k次。正常图形化界面安装安装X Windowyum groupinstall "X Window System"yum install unzip.x86_64 vim java-1.8.0-openjdk.x86_64 java-1.8.0-openjdk-devel.x86_64安装依赖软件包yum install binutils compat-libstdc++-33 elfutils-_oracle11.2.0需下载什么版本的export

无中继的DHCP配置-ZTE中兴路由器_中兴1800路由器dhcp-程序员宅基地

文章浏览阅读4.6k次。无中继的DHCP配置DHCP的作用: 动态配置IP地址,整个配置过程自动实现,终端无需设置 所有配置信息统一管理,不仅能够分配IP地址,还可以配置其他信息DHCP的优点: 提高网络配置效率,减少配置工作量,较少IP冲突的可能性DHCP server: 集中存放配置信息,响应客户端的请求与之交互并完成主机配置信息的分..._中兴1800路由器dhcp

随便推点

Python从入门到放弃(目录)-程序员宅基地

文章浏览阅读125次。Python基础第一篇:安装Python基础第二篇:初识Python基础第三篇:基本数据类型及运算Python基础第四篇:文件操作Python基础第五篇:函数初识Python基础第六篇:函数进阶Python基础第七篇:装饰器、迭代器、生成器Python基础第八篇:内置函数、匿名函数、递归Python基础第九篇:模块与包Python基础第十篇:常用模块..._python从入门到放弃(目录)

VScode 配置python3开发环境_${workspacefolder}/.env-程序员宅基地

文章浏览阅读1.1w次,点赞11次,收藏54次。本文转载自大兵小将0221《vscode 配置 python3开发环境》程序员宅基地。为了避免下次配置忘记,故而转载。1 安装插件python 这个是vscode提供的python 官方插件,提供了python代码的调试,自动补全,代码格式化等功能。vscode-icons 这个也是vscode官方提供的插件,作用是给vscode..._${workspacefolder}/.env

vsan加入不同型号服务器,VMware VSAN的特点与要求,与优缺点-程序员宅基地

文章浏览阅读3.5k次。VSAN的特点与要求,与优缺点VMware VSAN主要有5个特点:1、运行在标准x86服务器上2、分布式集群,把VM数据文件打散放在多个主机上,每个服务器的本地存储网络池化3、使用SSD作为读写缓存加速层,混合型策略,由SSD提供性能,普通机械硬盘提供容量,适用的市场范围更广4、VSAN中没有LUN也不需要做RAID 5或者RAID 0+1,使用VMDK为单位的对象存储,所有虚拟化性能、容量、调..._vsan是不是不需要raid

解决MySQL8.0报错:Unknown system variable 'validate_password_policy'_unknown system variable 'validate_password_policy-程序员宅基地

文章浏览阅读3.8w次,点赞40次,收藏114次。解决MySQL8.0报错:Unknown system variable 'validate_password_policy' 一、问题描述1、在安装MySQL8.0时,修改临时密码,因密码过于简单(如:123456),不符合MySQL密码规范,会触发一个报错信息: ERROR 1819 (HY000): Your password does not satisfy ..._unknown system variable 'validate_password_policy

解决jQuery UI API - 图标(Icons)_jquery ui icons.png-程序员宅基地

文章浏览阅读3.9k次。首先 在网上下载jQuery UI APIhttps://jqueryui.com/download/我用的jQuery1.7.1在静态页面上加载&amp;lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;/static/css/jquery-ui.css&quot;/&amp;gt;在jquery-ui.css 中 把图片的地址 用_jquery ui icons.png

Linux安装完成后添加新网卡_linux添加网卡-程序员宅基地

文章浏览阅读4.1k次,点赞2次,收藏19次。在安装完linux后,在系统里添加了一块网卡后,在/etc/sysconfig/network-scripts/目录下没有相应的配置文件ifcfg-eth1。在这种情况下,linux不会主动去添加配置文件ifcfg-eth1的。如果需要使用这块网卡,有二种方法:方法一:使用命令临时指派一个IP给这块新添加的网卡ifconfig eth1 192.168.0.1 netmask 255.255.255.0 up方法二:1.手工添加ifcfg-eth1这个配置文件,然后重启网络。先复制一份ifcf_linux添加网卡

推荐文章

热门文章

相关标签