![](https://i-blog.csdnimg.cn/blog_migrate/5f7e9e88e8d3c25e5c91680711f686ef.png)
排列问题
求这4个球的所有排列方式
暴力枚举方式。
public static void main(String[] args) {
char[] cc = {'A','B','C','D'};
int count = 0;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if(i==j)continue;
for(int k=0;k<4;k++){
if(k==i||k==j)continue;
for(int m=0;m<4;m++){
if(m==k||m==j||m==i)continue;
System.out.println(cc[i]+" "+cc[j]+" "+cc[k]+" "+cc[m]);
count++;
}
}
}
}
System.out.println(count);
}
分析这4层循环。
分别枚举了4个球在于其他球不重复情况下的情况
i 的 变化范围是 0 - 4
j 的 变化范围是 0 - 4 -1(不能和i重复)
k的 变化范围是 0 - 4 -2 (不能和i重复也不能和j重复)
m的 变化范围的 0 - 4 - 3 (不能和i重复也不能和j重复也不能也k重复)
结论4个数的全排列个数是 4 * 3 * 2 *1
求4个球 中取2个球的不同排列
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
char[] cc = {'A','B','C','D'};
int count = 0;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if(i==j)continue;
System.out.println(cc[i]+" "+cc[j]);
count++;
}
}
System.out.println(count);
}
}
分析这2层循环。
既然是从4个球中取2个球的全排列,那么2层循环模拟2个球分别是什么
i 的 变化范围是 0 - 4
j 的 变化范围是 0 - 4 -1(不能和i重复)
结论4个球 中取 2个的全排列个数是 4 * 3
看看这2层循环和上面4层循环的区别
此时已经可以完全解释的通百度上的那个全排列公式
n种颜色取m种的全排列 的种数
n的阶乘 除以 (n-m)的阶乘 :
原理 n 的阶乘的 n种 全排列一定是 n的阶乘
要取 其中 m的 全排列,
像之前的循环一样,原本是n重循环,此时应该 将多余层数循环(n-m)除以
全排列经典递归模拟:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
char[] cc = {'A','B','C','D'};
all(cc,0);
}
public static void all(char[] cc,int index){
if(index==cc.length){
System.out.println(Arrays.toString(cc));
return;
}
for(int i=index;i<cc.length;i++){
char temp = cc[i];cc[i]=cc[index];cc[index] = temp;
all(cc,index+1);
temp = cc[i];cc[i]=cc[index];cc[index] = temp;
}
}
}
组合问题
从球中任意取2个的取法。
(这个组合问题也是刚刚学会,强行解释一番)
组合和排列的区别:
排列会存在
红 橙、橙红
但是 组合 不会出现重复
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
char[] cc = {'A','B','C','D'};
int count = 0;
for(int i=0;i<4;i++){
for(int j=i+1;j<4;j++){
System.out.println(cc[i]+" "+cc[j]);
count++;
}
}
System.out.println(count);
}
}
对于,这个两层循环,可以思考 4 个球 中取 2 个球的全排列 4*3 = 12
用 12 除以,2的阶乘 2就是取几个球。 过滤掉 排列中重复的那些球,就可以得到组合的所有种类
总结,n个球中取m个球,的组合数就是 他的所有排列种类 除以 m的阶乘
这样去理解公式
用递归去求,m个球中取n个数的全组合数
public static int f(int m,int n){
if(m==n)return 1;
if(n==0)return 1;
return f(m-1,n-1) + f(m-1,n);
}
模拟组合递归法
import java.util.Arrays;
public class Main {
//不重复的组合问题
public static void main(String[] args) {
char[] cc = {'A','B','C','D'};
//枚举法
for(int i=0;i<4;i++){
for(int j=i+1;j<4;j++){
for(int k=j+1;k<4;k++){
System.out.println(cc[i]+""+cc[j]+""+cc[k]);
}
}
}
System.out.println();
g1(cc,new char[3],0,0);
System.out.println();
g2(cc,"",0,3);
}
//递归1
//cc原球种类
//ss已经取好的球
//index 应该从第几个球开始取
//n 现在应该取第几个球
public static void g1(char[] cc,char[] ss,int index,int n){
if(n==ss.length){
System.out.println(Arrays.toString(ss));
return;
}
for(int i=index;i<cc.length;i++){
ss[n] = cc[i];
g1(cc,ss,i+1,n+1);//加强注意,i+1 不是index+1
}
}
//递归2
//cc原球种类
//ss已经取好的球
//index 应该从第几个球开始取
//n 一共打算取几个球
//使用str的长度判断球取够了没
public static void g2(char[] cc,String str,int index,int n){
if(str.length()==n){
System.out.println(str);
return;
}
for(int i=index;i<cc.length;i++){
g2(cc,str+cc[i],i+1,n);
}
}
}
组合重复
X星球要派出一个5人组成的观察团前往W星。其中:A国最多可以派出4人。B国最多可以派出2人。C国最多可以派出2人。D国最多可以派出1人。E国最多可以派出1人。F国最多可以派出3人。那么最终派往W星的观察团会有多少种国别的不同组合呢?
模拟该组合
这里我分别使用了数组做形参,和字符串做形参两种方式进行模拟。
字符串做形参的好处是,字符串是一个常量,每次递归压栈都会创建新的字符串,所以不需要huis
import java.util.Arrays;
public class Main {
static char[] cc = { 'A', 'B', 'C', 'D', 'E', 'F' };
static int count = 0;
public static void main(String[] args) {
int[] data = { 4, 2, 2, 1, 1, 3 };// 每个元素的最大个数
int[] x = new int[6]; // 每个元素取几个
// f(data,x,0,3);//取三个,
f2(data, 0, 3, "");
System.out.println(count);
}
// k代表 现在正在取 那个元素
public static void f(int[] data, int[] x, int k, int goal) {
if (k == data.length) {
if (goal == 0) {
for (int i = 0; i < x.length; i++) {
for (int j = 0; j < x[i]; j++) {
System.out.print(cc[i]);
}
}
System.out.println();
count++;
}
return;
}
// data[k]和goal中的最小值就是说,我还能最多取几个 x[k]=i;//这个位置取几个; //再从下一个位置开始取
for (int i = 0; i <= Math.min(goal, data[k]); i++) {
//这个国家出几个人。
x[k]=i;
//进入递归
f(data, x, k + 1, goal - i);
}
// 模拟完这个位置回溯一下
x[k] = 0;
}
// 使用一个字符串做该次测试的变化条件
public static void f2(int[] data, int k, int n, String str) {
if (k == data.length) {
if (n == 0) {
System.out.println(str);
count++;
}
return;
}
String s2 = str;
for (int i = 0; i <= Math.min(data[k], n); i++) {
f2(data, k + 1, n - i, s2);
s2 += cc[k];
}
}
}