目录
1 问题描述:如何实现从n个数字放到k个桶中,并且每个桶中都有数字
参考资料labuladuo算法:
回溯算法牛逼:集合划分问题 :: labuladong的算法小抄
1 问题描述:如何实现从n个数字放到k个桶中,并且每个桶中都有数字
以数字的视角,每个数字尝试放入桶当中
public static void main(String[] args) {
//
int n = 5;
int k = 3;
int[] nums = new int[5];
List<List<Integer>> buckets = new ArrayList<>();
for (int i = 0; i < n; i++) {
nums[i] = i + 1;
}
for(int i=0;i<k;i++) {
buckets.add(new ArrayList<>());
}
new Main().traverse(nums, 0, buckets);
System.out.println("Hello world");
}
void traverse(int[] nums, int idx, List<List<Integer>> buckets) {
if (idx >= nums.length) {
//返回合法的分配方法
if(validBucket(buckets, 0)) {
System.out.println(buckets.toString());
}
return;
}
for (int i = 0; i < buckets.size(); i++) {
//简单剪枝,减少遍历次数
if(!validBucket(buckets, nums.length - idx)) {
return;
}
List<Integer> bucket = buckets.get(i);
bucket.add(nums[idx]);
traverse(nums, idx+1, buckets);
bucket.remove(bucket.size()-1);
}
}
boolean validBucket(List<List<Integer>> buckets, int leftNum) {
for(int i=0;i<buckets.size();i++) {
if(buckets.get(i).size() <=0) {
leftNum--;
}
}
return leftNum>=0;
}
2 求取数组的子集:给定一个数组,输出它的所有子集
方法一: 数学归纳法-每次的结果可以根据上一次的结果得到,代码如下:
void traverse2(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
result.add(new ArrayList<>());
for(int i=0;i<nums.length;i++) {
int size = result.size();
for(int j=0;j<size;j++) {
List<Integer> element = new ArrayList<>();
result.get(j).forEach(o -> {
element.add(o);
});
element.add(nums[i]);
System.out.println(element.toString());
result.add(element);
}
}
}
方法二:回溯法实现-每次选择元素是否加入到相关的子集中
/**
*
* @param nums -- 数组
* @param index -- 数组下标,需要考虑是否加入的数组元素下标
* @param result -- 最后的结果
*/
void traverse(int[] nums,int index, List<Integer> result) {
System.out.println(result.toString());
for(int i=index;i<nums.length;i++) {
result.add(nums[i]);
traverse(nums, i + 1, result);
result.remove(result.size()-1);
}
}