1. 之前的取球问题是m个不同的球中取出n个共有多少种的取法,而现在我们要求解的是元素中存在重复的问题,需要求解的问题是在字符串"AABBBC"中3个字母共有多少种的取法
2. 由于问题是不一样的,所以我们求解的方法也是不一样的,下面是具体解决的思路
① 首先我们要声明一个数组来记录当前位置出现的次数是多少,上面的例子是data[] = {2,3,1},还有就是需要设置一个变量来表示当前的位置,对于上面的三个位置我们可以依次进行取出元素的个数,例如对于第一个位置我们可以取出零个,一个,两个,对于第二个的位置我们可以取出一个,两个,三个,对于第三个位置我们可以取出零个,一个
② 经过上面的分析之后我们发现需要使用一个for循环来进行递归分别尝试在当前的位置上去取出若干个元素个数,所以需要在for循环中进行递归,尝试所以的可能性,而且for循环的判断条件是当前位置可以取出来的最大数量并且需要小于取出的目标值,因为当前我可以取得有这么多而且我需要取得有那么多这两个条件要进行限制才对
for(int i = 0; i <= data[k] && i <= goal; i++){
//尝试在k这个位置取出i个
arr[k] = i;
dfs(data, arr, k + 1, cur + i, goal);
arr[k] = 0;
}
③ 参数的变化,对于当前位置我们取出i个元素之后那当前取得元素数量应该加上i,位置应该加1,然后进行下一次的递归,出口先要判断当前的取得元素值是否满足目标值,假如满足直接return,不满足需要判断k这个位置是否等于与数组的长度,如果等于了那么也需要进行return了
④ 回溯的问题,需要注意的是我在出口是要打印数组对应的位置上取了多少个的元素,所以需要进行回溯这样假如在之前的数组的第三个位置是有值的那么下一次递归的时候第二个位置就已经满足条件了那么不回溯的话数组中的元素就是错误的
总结一下:最重要的是要考虑到每个位置尝试着取i个元素的个数,这样接下来使用递归来进行尝试每一种的可能性就非常方便了
因为这样的尝试可能性的问题对于递归来说是非常解决的,
3. 具体的代码如下:
public class Main {
static int count = 0;
public static void main(String[] args) {
//"AABBBCC"
//int data[] = {2, 1};
int data[] = {2, 3, 1};
int arr[] = new int[data.length];
dfs(data, arr, 0, 0, 3);
System.out.println(count);
}
private static void dfs(int[] data, int[] arr, int k, int cur, int goal) {
if(cur == goal){
for(int i = 0; i < arr.length; i++){
System.out.print("[" + (i + 1) + "] = ");
System.out.print(arr[i] + " ");
}
System.out.print("\n");
count++;
return;
}
if(k == arr.length){
return;
}
for(int i = 0; i <= data[k] && i <= goal; i++){
arr[k] = i;
dfs(data, arr, k + 1, cur + i, goal);
arr[k] = 0;
}
}
}