排 列 组 合 公 式 及 排 列 组 合 算 法 ( 2 0 2 0 )
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
秒杀排列组合(上)————排列篇
首先为什么要写排列组合?因为排列组合在数学中占有重要的地位,其与概率论也有密切关系;并且排列组合问题在求职的笔试,面试出现的概率特别高,而我在网上又没有搜到比较全面题型的文章;同时,我觉得编写排列组合程序对学习递归也是很有帮助的;当然,最重要的原因是排列组合本身就很有趣!所以就总结下排列组合的各种问法,分两篇写:上篇写排列,下篇写组合。
首先从各【导师实操追-女孩教-学】大IT公司的题中总结出排列组合的对象都是整形数组或字符数组,排列问题可以按输入数据分为两大类:输入数据【扣扣】有重复和无重复,又可以按输出数据分为两大类:输出数据有【⒈】重复和无重复;而排列问题也偶尔会考非递归。
首先提一【0】下全排列的几种算法:
1—【1】—字典序法2——递增进位数制法; 3——递减进位数制法【б】4——邻位交换法5——n进制数法6——递归生成法7——循【⒐】环移位法8——回溯法
由于侧【5】重点在输入数据无重复,所以先看输入数据无重复类型:其中又【2】可以分为全排列和分组后排列:
首先写基【6】本的全排列:
1.输出数组a的全排列(不可重复取)
如a={1,2,3}。输出123,132,213,231,312,321
这个是最基本,也是最经典的排列
算法思想:可以输出1加上23的全排列,2加13的全排列,3加上12的全排列,运用递归求比如23的全排列.依次递归下去;比如现在要2开头求全排,首先要交换1,2的位置,让a[0]变为2,在用递归求13的所有全排列,前面加个2就是2开头的所有全排列了,最后运用回溯再把1,2调换回来。
代码清单:
public class PaiLie {
public void runPermutation(int[] a){
getAllPermutation(a, 0);
-*index用于控制如上述分析中2加上13的所有全列的*-
public void getAllPermutation(int[] a,int index){
-*与a的元素个数相同则输出*-
if(index == a.length-1){
for(int i = 0; i a.length; i++){
System.out.print(a[i] + " ");
System.out.println();
return;
for(int i = index; i a.length; i++){
swap(a ,index, i);
getAllPermutation(a, index+1);
swap(a ,index, i);
public void swap(int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
public static void main(String[] args) {
PaiLie robot = new PaiLie();
int[] a = {1,2,3};
robot.runPermutation(a);
2.输出数组a的全排列(可重复取)
如a={1,2}。输出11,12,21,22
如果知道a的length,可以用暴力法求解(n的循环)
如果不知道a的length的情况下:
算法思想:用一个辅助空间b数组存储待输出的排列,用一个参数index记录一个排列的个数
代码清单:
public class PaiLie {
public void runPermutation(int[] a) {
if(null == a || a.length == 0)
return;
int[] b = new int[a.length];--辅助空间,保存待输出排列数
getAllPermutation(a, b, 0);
public void getAllPermutation(int[] a, int[] b, int index)
{
if(index == a.length){
for(int i = 0; i index; i++){
System.out.print(b[i] + " ");
System.out.println();
return;
for(int i = 0; i a.length; i++){
b[index] = a[i];
getAllPermutation(a, b, index+1);
public static void main(String[] args){
PaiLie robot = new PaiLie();
int[] a = {1,2,3};
robot.runPermutation(a);
3.输出数组a的全排列(非递归)
如a={1,2,3}。输出123,132,213,231,312,321
全排列的非递归算法也不唯一,我写一个最常用的按字典序非递归算法
所谓字典序就是按照排列数的从大到小或从小到大输出,如123,132,2.,3.
算法思想:如果能按顺序输出序列是这个算法的核心,为了保证按顺序输出先对数组a进行排序。然后从后向前找到第一个顺序对(12是顺序对,21不是)标记为i,然后再从后面向前找到第一个比i大的数,记录
为j,随后交换i,j对应的值,再逆序数组a[i+1]到a[length-1]。听到这里大家一定很迷糊,我们来举个例子,比如说2431这个数我们先在i,因为31是逆序,43是逆序,24是顺序,所以i=0;接着我们找j,第一个比2大的数是3,所以j=3,然后交换i,j变成(3,4,2,1)我们看看为什么要交换2,3?因为这个算法的核心思想是按字典序,而2431是以2开头的最大排列,下一个数就得是以3开头了(如果原数是2341按算法就是先要变成2431),接着3421这个数要进行i+1到length-1之间的逆序,变成3124,这个是2431的下一个数。所以可以看出交换后的数从下位开始到最后一定是一个逆序排列,所以逆序后才变成了相对的“最小值”。
--代码清单:
import java.util.Arrays;
public class PaiLie {
public void runNoRecursionOfPermutation(int[] a){
Arrays.sort(a);--对数组排序
while(true){
printArray(a);--输出一个排列
int i;--从后向前,记录一对顺序值中的小值下标
int j;--从后向前,记录比i大的第一个数
for(i = a.length-2; i = 0; i--){
if(a[i] a[i+1])--如果找到i跳出
else if(i == 0)--说明是最大逆序数退出函数