请求将C语言中的递归函数f(m,n)转换为迭代实现
迭代实现方案:动态规划自底向上法
好的,咱们来搞定这个递归转迭代的问题!首先得拆解一下你这个递归函数的逻辑,看看它的依赖关系——递归是自顶向下调用,容易有栈溢出和重复计算的问题,迭代咱们用动态规划自底向上的思路来实现,既高效又稳定。
先明确原递归函数的逻辑:
int f(int m,int n) {
if (n == 0) return m;
if (m == 0) return n;
return f(m+1, n-1) + f(m, n-1) + f(m-1, n-1) + f(m-1, n);
}
核心思路分析
这个函数的base case很清晰:
- 当
n=0时,返回m; - 当
m=0时,返回n; - 其他情况,
f(m,n)依赖四个子问题的结果:f(m+1,n-1)、f(m,n-1)、f(m-1,n-1)、f(m-1,n)。
这里有个特殊点:f(m,n)依赖m更大的子问题(f(m+1,n-1)),这意味着如果我们按n从0到目标值递增计算,对于每个n,需要从大到小遍历m,这样才能保证计算f(m,n)时,f(m+1,n-1)已经被算出来了。
另外,我们需要确定m的最大范围:假设目标是计算f(m_target, n_target),那么最大的m会是m_target + n_target——因为每次n减1,m最多加1,从n_target到0最多加n_target次,所以m的上限设为m_target + n_target就足够覆盖所有子问题。
C语言迭代实现代码
#include <stdio.h> #include <stdlib.h> int f_iterative(int m_target, int n_target) { // 计算需要覆盖的最大m值,多留一个位置避免越界 int max_m = m_target + n_target; int max_n = n_target; // 动态规划数组:dp[i][j] 对应 f(i,j) 的值 int** dp = (int**)malloc((max_m + 2) * sizeof(int*)); for (int i = 0; i <= max_m + 1; i++) { dp[i] = (int*)malloc((max_n + 1) * sizeof(int)); } // 初始化base case:n=0时,f(m,0)=m for (int i = 0; i <= max_m + 1; i++) { dp[i][0] = i; } // 初始化base case:m=0时,f(0,n)=n for (int j = 0; j <= max_n; j++) { dp[0][j] = j; } // 按n从1到目标值递推 for (int j = 1; j <= max_n; j++) { // 从大到小遍历m,保证计算dp[i][j]时,dp[i+1][j-1]已就绪 for (int i = max_m; i >= 1; i--) { int term1 = dp[i+1][j-1]; // f(m+1, n-1) int term2 = dp[i][j-1]; // f(m, n-1) int term3 = dp[i-1][j-1]; // f(m-1, n-1) int term4 = dp[i-1][j]; // f(m-1, n) dp[i][j] = term1 + term2 + term3 + term4; } } // 保存目标结果 int result = dp[m_target][n_target]; // 释放动态分配的内存 for (int i = 0; i <= max_m + 1; i++) { free(dp[i]); } free(dp); return result; } // 原递归函数,用于测试对比 int f_recursive(int m, int n) { if (n == 0) return m; if (m == 0) return n; return f_recursive(m+1, n-1) + f_recursive(m, n-1) + f_recursive(m-1, n-1) + f_recursive(m-1, n); } int main() { // 测试用例1:m=2,n=2 int m = 2, n = 2; printf("递归版本结果:%d\n", f_recursive(m, n)); printf("迭代版本结果:%d\n", f_iterative(m, n)); // 测试用例2:m=1,n=3 m = 1; n =3; printf("\n递归版本结果:%d\n", f_recursive(m, n)); printf("迭代版本结果:%d\n", f_iterative(m, n)); return 0; }
代码说明
- 内存分配:给
max_m多留了一个位置(max_m+1),这样计算dp[i+1][j-1]时不会出现数组越界的问题,不用额外判断边界。 - 递推顺序:对于每个
n,从大到小遍历m,确保f(m+1,n-1)已经被计算完成。 - 内存释放:记得释放动态分配的二维数组,避免内存泄漏。
另一种思路:栈模拟递归
如果更倾向于模拟递归的调用过程,可以用栈来保存待计算的(m,n)对,同时用数组记录已计算的结果(避免重复计算)。不过这种方法的效率不如动态规划,因为会有栈操作的开销,且需要处理子问题的依赖顺序,适合理解递归转迭代的原理,但实际工程中更推荐动态规划方案。
内容的提问来源于stack exchange,提问作者Shiro98
相关产品推荐
相关产品推荐

