1. 组合问题与递归解法基础
组合问题在计算机科学和数学中有着广泛的应用场景,比如从n个物品中选出k个物品的所有可能情况。这类问题在概率统计、密码学、算法设计等领域都很常见。理解组合问题的递归解法,不仅能帮助我们解决具体问题,更能培养递归思维,这对程序员来说至关重要。
组合问题的数学本质是计算组合数C(n,k),也就是从n个不同元素中取出k个元素的组合数。根据组合数学公式:
C(n,k) = n! / (k!(n-k)!)
但这个阶乘计算在编程实现时效率不高,特别是当n较大时容易导致数值溢出。因此我们需要寻找更高效的算法实现。
递归解法基于一个关键观察:对于任何一个特定元素,我们有两种选择:
- 包含这个元素:那么我们需要从剩下的n-1个元素中选择k-1个元素
- 不包含这个元素:那么我们需要从剩下的n-1个元素中选择k个元素
这就形成了递归关系:C(n,k) = C(n-1,k-1) + C(n-1,k)
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 递归函数设计与实现
2.1 基础递归实现
让我们先看一个最基础的递归实现,也就是用户提供的代码框架:
c复制long long pick(int n, int k) {
if(k == n || k == 0)
return 1;
else
return pick(n-1, k-1) + pick(n-1, k);
}
这个实现有几个关键点需要注意:
- 基线条件(递归终止条件):当k等于0(选0个)或k等于n(全选)时,只有1种选择方式
- 递归关系:将问题分解为两个子问题的和
- 使用long long类型:防止计算结果溢出
注意:用户提供的原始代码中有一个小错误,在递归调用中应该是pick(n-1,k)而不是pick(n,k-2)。正确的递归关系应该是pick(n-1,k-1) + pick(n-1,k)
2.2 递归调用过程解析
让我们以pick(4,2)为例(从ABCD四个元素中选2个),看看递归调用的具体过程:
-
pick(4,2)
- 不等于基线条件,所以分解为:
- pick(3,1) + pick(3,2)
-
pick(3,1)
- 分解为 pick(2,0) + pick(2,1)
