回溯
组合中按暴力解法来的话如果k太大会造成for循环嵌套太多,用递归来代替,每层递归嵌套一个for循环
注意递归的顺序,return一次返回上一次递归,该代码中for循环结束了也返回上一次递归。
注意
下代码中递归时参数是j+1以便继续向下追踪而不能是startindex+1
for(j = startindex;j<=n;j++)
{
line[linetop++] = j;
wayback(k,n,j+1);
linetop--;
}
int* line;
int linetop;
int** ans;
int anstop;
void wayback(int k,int n,int startindex)
{
//一个组合已经找到了,把它加入到答案数组里面去
if(linetop == k)
{
int* temp = (int*)malloc(sizeof(int)*k);
for(int i = 0;i<k;i++)
{
temp[i] = line[i];
}
ans[anstop++] = temp;
return ;//返回上一层继续往下找
}
int j;
for(j = startindex;j<=n;j++)
{
line[linetop++] = j;
wayback(k,n,j+1);
linetop--;
}
}
int** combine(int n, int k, int* returnSize, int** returnColumnSizes){
line = (int*)malloc(sizeof(int)*k);
ans = (int**)malloc(sizeof(int*)*1000);
linetop = 0;
anstop = 0;
wayback(k,n,1);
*returnSize = anstop;
//returnColumnSizes数组存储ans二维数组对应下标中一维数组的长度(都为k)
*returnColumnSizes = (int*)malloc(sizeof(int) *(*returnSize));
int i;
for(i = 0; i < *returnSize; i++) {
(*returnColumnSizes)[i] = k;
}
//返回ans二维数组
return ans;
}
对类似题目中函数里面二级指针的初步理解
如下是调用该函数的main函数,函数参数里面的而及指针指向的其实是一维数组,记录每一行有几列。
int main(){
int n = 4, k = 2;
int returnSize;
int* returnColumnSizes;
int** ans = combine(n, k, &returnSize, &returnColumnSizes);
for(int i = 0; i < returnSize; i++){
for(int j = 0; j < k; j++){
printf("%d ", ans[i][j]);
}
printf("\n");
}
return 0;
}
剪枝
到后面几个到不了k个,可以直接就不遍历如n=5,k=3,345可以组成,从4开始只有两个无法组成组合。
再往下层也是同理,从某个位置往后就无法成功到达所需要的个数
可将
for(j = startindex;j<=n;j++)
{
line[linetop++] = j;
wayback(k,n,j+1);
linetop--;
}
改为
for(j = startIndex; j <= n- (k - pathTop) + 1;j++) {
//将当前结点放入path数组
path[pathTop++] = j;
//进行递归
backtracking(n, k, j + 1);
//进行回溯,将数组最上层结点弹出
pathTop--;
}
```