Java 全排列与组合

Posted ZSYL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 全排列与组合相关的知识,希望对你有一定的参考价值。

排列组合是组合学最基本的概念。
所谓排列,就是指从给定个数的元素中取出指定个数的元素进行排序。
组合则是指从给定个数的元素中仅仅取出指定个数的元素,不考虑排序。
----- 百度百科

全排列

概念

一般地说,从n个不同元素中,任取m(m≤n)个元素,按照一定的顺序排成一列,这就叫做从n个元素中取出m个元素的一个排列。

公式

在这里插入图片描述
当 m=n 时,便称为全排列

此外规定0! = 1

因此:全排列公式:n!

分析

举例:
1,2,3的全排列有:

1,2,3
1,3,2
2,1,3
2,3,1
3,1,2
3,2,1

考虑建立二叉树
在这里插入图片描述
对于每一种排列的,都需要选择 首元素,之后第一个元素与剩下的元素依次类推,每一步都选择一个元素,直到全部元素选择完毕。
考虑使用递归,底层是栈,每一次出栈,后我们还原上一次的现场,重现修改之前选择的元素,再次进栈。

代码展示

import java.util.Arrays;

public class Main {
    static int[] a;
    public static void main(String[] args) {
        a = new int[]{1, 2, 3, 4};
        fullSort(0, a.length-1);
    }
    public static void fullSort(int s, int e) {
        // 递归结束条件
        if (s == e) {
            System.out.println(Arrays.toString(a));
        }
        // 脑海中形成二叉树的形状,对于当前需要选择一个元素做首,之后从该元素向下递归
        // 对于 s-e 所有元素都可放在首,因此 for循环,每次递归后,回溯需要还原现场
        for (int i = s; i <= e; i++) {
            // 交换首元素
            swap(s, i);
            fullSort(s+1, e);
            // 交换元素复原,不影响下一次的选择
            swap(s, i);
        }
    }
    // 交换元素函数
    public static void swap(int i, int j) {
        int temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
}

结果
在这里插入图片描述

组合

概念

组合的定义

从n个不同元素中,任取m(m≤n)个元素并成一组,叫做从n个不同元素中取出m个元素的一个组合;
从n个不同元素中取出m(m≤n)个元素的所有组合的个数,叫做从n个不同元素中取出m个元素的组合数。
用符号 C(n,m) 表示。

公式

在这里插入图片描述
或者是:
n * (n-1)…(n-m+1) / m!

枚举1-n所有组合,随机选取任意多个

分析

例如
n=2,有3种情况:

1
2
12

对于1-n 的每一个数,我们有选择与不选择两种情况,对于每次选择之后,求解子问题,一直到结束条件,考虑使用递归,注意每次选择后,需要还原现场。

代码展示

import java.util.Scanner;
import java.util.Vector;

// 枚举1-n所有组合,随机选取任意多个
public class _01_enumerateAll {
    static int n;
    static Vector<Integer> vector = new Vector<>();

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        calc(1);
    }

    public static void calc(int x) {
    	// 递归结束条件,遍历到最后
        if (x == n+1) {
            for (int i : vector) {
                System.out.print(i + " ");
            }
            System.out.println();
            return;
        }
        // 不选x分支
        calc(x+1);
        // 选择x
        vector.add(x);
        // 求解子问题
        calc(x+1);
        // 回溯上一个问题之前,还原现场
        vector.remove((Object)x);
    }
}

枚举1-n所有组合,随机选取m个数

与上面类似,只需修改递归结束条件即可

代码展示

import java.util.Scanner;
import java.util.Vector;

// 枚举1-n所有组合,随机选取m个数
public class _02_enumerateN {
    static int n, m;
    static Vector<Integer> vector = new Vector<>();

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        m = sc.nextInt();

        calc(1);

    }

    public static void calc(int x) {
    	// 剪枝操作,减去不必要的递归,提前出栈
    	// 当选择的数 > m 时,或者 剩下的数,不够选时,return;
        if (vector.size() > m || vector.size() + (n-x+1) < m)
            return;

        if (vector.size() == m) {
            for (int i : vector) {
                System.out.print(i + " ");
            }
            System.out.println();
            return;
        }
        // 不选x分支
        calc(x+1);
        // 选择x
        vector.add(x);
        // 求解子问题
        calc(x+1);
        // 回溯上一个问题之前,还原现场
        vector.remove((Object)x);
    }
}

感谢
努力
加油

以上是关于Java 全排列与组合的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 P1706 全排列问题(Java版)

关于各种排列组合java算法实现方法

全排列与全组合

获取所有组合算法获取全排列算法(java)

分治法实现1-N的数字按字典序全排列组合 Java语言

总结:组合与排列