回溯法 = 深度搜索 + 剪枝 且深度搜索一般使用递归来实现,程序代码相对简洁
代码模板
/**
* dfs 模板.
* @param[in] input 输入数据指针
* @param[inout] cur or gap 标记当前位置或距离目标的距离
* @param[out] path 当前路径,也是中间结果
* @param[out] result 存放最终结果
* @return 路径长度,如果是求路径本身,则不需要返回长度
*/
void dfs(type *input, type *path, int cur or gap, type *result) {
if (数据非法) return; // 终止条件
if (cur == input.size( or gap == 0)) { // 收敛条件(找到结果)
将path 放入result
}
for(...) { // 执行所有可能的扩展动作
if (可以剪枝) return;
执行动作,修改path
dfs(input, step + 1 or gap--, result);
恢复path
}
}
递归函数的参数的选择,要遵循四个原则:
1、必须要有一个临时变量(可以就直接传递一个字面量或者常量进去)传递不完整的解,因为每一步选择后,暂时还没构成完整的解,这个时候这个选择的不完整解,也要想办法传递给递归函数。也就是,把每次递归的不同情况传递给递归调用的函数。
2、可以有一个全局变量,用来存储完整的每个解,一般是个集合容器(也不一定要有这样一个变量,因为每次符合结束条件,不完整解就是完整解了,直接打印即可)。
3、最重要的一点,一定要在参数设计中,可以得到结束条件。一个选择是可以传递一个量n,也许是数组的长度,也许是数量,等等。
4、要保证递归函数返回后,状态可以恢复到递归前,以此达到真正回溯。
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
说明:
所有数字(包括 target)都是正整数。
解集不能包含重复的组合。
示例 1:
输入: candidates = [2,3,6,7], target = 7,
所求解集为:
[
[7],
[2,2,3]
]
示例 2:
输入: candidates = [2,3,5], target = 8,
所求解集为:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
gap-- 的使用方法
void dfs(int start,int *path,int index,int *candidates,int candidatesSize, int target, int value,int **result,int *size,int *returnColumnSizes)
{
if (value == target) {
result[*size]=(int *)malloc(sizeof(int) * index);
for(int i = 0; i < index; i++) {
result[*size][i] = path[i];
}
returnColumnSizes[*size] = index;
*size += 1;
return;
}
for(int i = start;i < candidatesSize; i++)
{
if ((target - value) < candidates[i]) return;
path[index++] = candidates[i];
dfs(i, path, index, candidates, candidatesSize, target, value + candidates[i], result, size, returnColumnSizes);
index--;
}
}
int cmp (const void *a , const void *b)
{
return *((int *)a) - *((int *)b);
}
int** combinationSum(int* candidates, int candidatesSize, int target, int* returnSize, int** returnColumnSizes){
if (!candidates || candidatesSize < 0) {
*returnSize = 0;
*returnColumnSizes = NULL;
return NULL;
}
qsort(candidates, candidatesSize, sizeof(candidatesSize), cmp);
for (int i = 0; i < candidatesSize; i++) {
//printf("%d, ", candidates[i]);
}
*returnColumnSizes = (int *)calloc(1024, sizeof(int));
int path[1024];
int **result = (int **)calloc(1024, sizeof(int*));
int size = 0;
dfs(0 , path, 0, candidates, candidatesSize, target, 0, result, &size, *returnColumnSizes);
*returnSize = size;
return result;
}
step + 1 的使用方法
/**
* Return an array of arrays of size *returnSize.
* The sizes of the arrays are returned as *returnColumnSizes array.
* Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
*/
void dfs(int start,int *path,int index,int *candidates,int candidatesSize, int target, int value,int **result,int *size,int *returnColumnSizes)
{
if (value == target) {
result[*size]=(int *)malloc(sizeof(int) * index);
for(int i = 0; i < index; i++) {
result[*size][i] = path[i];
}
returnColumnSizes[*size] = index;
*size += 1;
return;
}
for(int i = start;i < candidatesSize; i++)
{
if ((target - value) < candidates[i]) return;
path[index++] = candidates[i];
dfs(i, path, index, candidates, candidatesSize, target, value + candidates[i], result, size, returnColumnSizes);
index--;
}
}
int cmp (const void *a , const void *b)
{
return *((int *)a) - *((int *)b);
}
int** combinationSum(int* candidates, int candidatesSize, int target, int* returnSize, int** returnColumnSizes){
if (!candidates || candidatesSize < 0) {
*returnSize = 0;
*returnColumnSizes = NULL;
return NULL;
}
qsort(candidates, candidatesSize, sizeof(candidatesSize), cmp);
for (int i = 0; i < candidatesSize; i++) {
//printf("%d, ", candidates[i]);
}
*returnColumnSizes = (int *)calloc(1024, sizeof(int));
int path[1024];
int **result = (int **)calloc(1024, sizeof(int*));
int size = 0;
dfs(0 , path, 0, candidates, candidatesSize, target, 0, result, &size, *returnColumnSizes);
*returnSize = size;
return result;
}
本文详细介绍了回溯法的基本概念,将其定义为深度优先搜索加剪枝策略,并通过具体示例阐述了如何利用递归实现回溯法解决组合问题,提供了清晰的代码模板和实践案例。

2028

被折叠的 条评论
为什么被折叠?



