import java.util.ArrayList;
/**
* 组合算法
* 本程序的思路是开一个数组,其下标表示1到m个数,数组元素的值为1表示其下标
* 代表的数被选中,为0则没选中。
* 首先初始化,将数组前n个元素置1,表示第一个组合为前n个数。
* 然后从左到右扫描数组元素值的“10”组合,找到第一个“10”组合后将其变为
* “01”组合,同时将其左边的所有“1”全部移动到数组的最左端。
* 当第一个“1”移动到数组的m-n的位置,即n个“1”全部移动到最右端时,就得
* 到了最后一个组合。
* 例如求5中选3的组合:
* 1 1 1 0 0 //1,2,3
* 1 1 0 1 0 //1,2,4
* 1 0 1 1 0 //1,3,4
* 0 1 1 1 0 //2,3,4
* 1 1 0 0 1 //1,2,5
* 1 0 1 0 1 //1,3,5
* 0 1 1 0 1 //2,3,5
* 1 0 0 1 1 //1,4,5
* 0 1 0 1 1 //2,4,5
* 0 0 1 1 1 //3,4,5
*
* @author songxh
* @create 2022-03-15-11:06
*/
public class 解决排列组合问题 {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5,6,7};//在这些数里面找出n个数的组合
int[] temp = new int[7];
int n = 3;//表示那啥结果的位数
ArrayList list = new ArrayList();
//将temp数组全部赋值0
for (int i = 0; i < temp.length; i++) {
temp[i] = 0;
}
//给tem数组初始前 n 个赋值为 1 ;
for (int i = 0; i < n; i++) {
temp[i] = 1;
}
boolean flag = true; //while循环的条件
boolean flagT;
while (flag) {
flagT=true;//初始化,便于后面判断是否退出循环
int t=0;//用于记录找到 1 0 时 1 的下标
int pos=0;//用于记录t下标前有多少个 1
list.add(print(arr, temp, n)); //最开始,第一第二第三个数的组合也是其一
for (int i = 0; i < temp.length-1; i++) { //遍历数组
if (temp[i]==1 && temp[i+1]==0){ //查找为 1 0 的下标并交换成 0 1
temp[i]=0;
temp[i+1]=1;
t=i;//记录此时1 的下标
break;
}
}
for (int i = 0; i < t; i++) { //查找 t 前有多少个 1
if (temp[i]==1){
pos++;
}
}
for (int i = 0; i < t; i++) {//将 t 前的所有 1 移动到最左边
if (i<pos){
temp[i]=1;
}else {
temp[i]=0;
}
}
//判断是否全部到达最右边即是否遍历完
for (int i = arr.length-n; i < arr.length; i++) {
if (temp[i]==0){
flagT=false; //若最后 n 位数有为 0 ,则没有遍历完
break;
}
}
if (flagT){
flag=false; //退出循环
}else {
flag=true;//如果flagT为false,就继续循环
}
}
//退出循环后,即处于所有 1 都在最右边的状态
list.add(print(arr,temp,n));//此状态依旧需要加上
//遍历集合
for (int i = 0; i < list.size(); i++) {
int[] a = (int[])list.get(i);//因为存的数组进去故而需要强转
for (int j = 0; j < a.length; j++) {
System.out.print(a[j]);
}
System.out.println();//换行
}
}
private static int[] print(int[] arr, int[] temp, int n) {
int[] res=new int[n];
int index=0;
for (int i = 0; i < temp.length; i++) {
if (temp[i]==1){
res[index]=arr[i];
index++;
}
}
return res;
}
}
注释很详细!