1. 给定一个元素个数为N的集合(其中元素互不相同),在其中选择M个元素组成子集,共有多少种选法。举例:输入[A,B,C] ,M=2,输出[[A,B],[A,C],[B,C]]
算法2.0
public static void main(String[] args) {
ArrayList resultList = new ArrayList();
method2(Arrays.asList(1, 2, 3, 4, 5, 6, 7), null, resultList, 1, 0);
System.out.println(resultList);
resultList = new ArrayList();
method2(Arrays.asList(1, 2, 3, 4, 5, 6, 7), null, resultList, 2, 0);
System.out.println(resultList);
resultList = new ArrayList();
method2(Arrays.asList(1, 2, 3, 4, 5, 6, 7), null, resultList, 3, 0);
System.out.println(resultList);
resultList = new ArrayList();
method2(Arrays.asList(1, 2, 3, 4, 5, 6, 7), null, resultList, 4, 0);
System.out.println(resultList);
resultList = new ArrayList();
method2(Arrays.asList(1, 2, 3, 4, 5, 6, 7), null, resultList, 5, 0);
System.out.println(resultList);
resultList = new ArrayList();
method2(Arrays.asList(1, 2, 3, 4, 5, 6, 7), null, resultList, 6, 0);
System.out.println(resultList);
resultList = new ArrayList();
method2(Arrays.asList(1, 2, 3, 4, 5, 6, 7), null, resultList, 7, 0);
System.out.println(resultList);
}
/**
* @param argsList 参数
* @param valueList 上一级的值
* @param resultList 结果集
* @param m 结果集目标长度
* @param start 开始索引
*/
public static void method2(List argsList, List valueList, List<List> resultList, int m, int start) {
for (int i = start; i < argsList.size(); i++) {
List list = new ArrayList();
if (null != valueList) {
list.addAll(valueList);
}
list.add(argsList.get(i));
if (list.size() == m) {
resultList.add(list);
continue;
}
method2(argsList, list, resultList, m, ++start);
}
}
算法1.0:(错误的)(感谢读客唯丶丶丶:指出)
public static void main(String[] args) {
System.out.println(method(Arrays.asList(1, 2, 3, 4, 5, 6, 7), 1));
System.out.println(method(Arrays.asList(1, 2, 3, 4, 5, 6, 7), 2));
System.out.println(method(Arrays.asList(1, 2, 3, 4, 5, 6, 7), 3));
System.out.println(method(Arrays.asList(1, 2, 3, 4, 5, 6, 7), 4));
System.out.println(method(Arrays.asList(1, 2, 3, 4, 5, 6, 7), 5));
System.out.println(method(Arrays.asList(1, 2, 3, 4, 5, 6, 7), 6));
System.out.println(method(Arrays.asList(1, 2, 3, 4, 5, 6, 7), 7));
}
public static List<List> method(List argsList, int m) {
List result = new ArrayList<>();
for (int i = 0; i < argsList.size(); i++) {
List arg = new ArrayList<>();
arg.add(argsList.get(i));
if (m == 1) {
// 如果只有1个数字的组合
result.add(arg);
continue;
}
// j是 第二位数的索引
int j = i + 1;
// count 是圈数
int count = 0;
// argsList.size() - j + 1 >= m 主要是判断后面的数字还需不需要循环
// 例子:1 2 3 4 如果我是需要3个数的组合,那你的循环是不会到3的,因为3后面只有4,最多是2个数的组合,只会到2,2后面有3和4,才能符合3个数的组合
while (argsList.size() - j + 1 >= m) {
arg = new ArrayList<>();
arg.add(argsList.get(i));
int max = i;
for (int l = 0; arg.size() < m - 1; l++) {
// 这里的作用主要是获取最后一位数之前的全部数
// 例子 1 2 3 4 5 , 4位数的组合, 我的想法是 先获取 1 2 3 公共的前缀,然后 遍历4和5
arg.add(argsList.get(j + l));
max = j + l;
}
// k 是最后一位数的索引
int k = max + count + 1;
while (arg.size() != m) {
// 这里就是为了遍历最后一个数字
arg.add(argsList.get(k++));
}
result.add(arg);
if (k == argsList.size()) {
// 当k等于最后一位数时,说明 已经遍历完了,第二位数字需要跳到下一位,
// 例子 1 2 3 4 ,3位数组合,当k等于索引3的时候,说明 123, 124都遍历完了,需要跳到 13开头
j++;
count = 0;
if (m == 2) {
break;
}
continue;
}
// 圈数累加
count++;
}
}
return result;
}