动态规划的递归写法和递推写法

本文深入解析了动态规划这一算法思想,介绍了其基本原理、适用场景及两种实现方式:递归(记忆化搜索)与递推。以斐波那契数列和数塔问题为例,详细阐述了如何利用动态规划解决问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

动态规划是一种非常精妙的算法思想,它没有固定的写法、及其灵活,常常需要具体问题具体分析。

11.1.1什么是动态规划

动态规划是一种用来解决一类最优化问题的算法思想。简单来说就是将一个复杂的问题分解成若干个子问题,通过综合子问题的最优解来得到原问题的最优解。DP会将每个求解过的子问题的解记录下来,这有当下一次碰到同样的子问题时,就可以直接使用之前的记录结果,提高了计算效率。
一般可以使用递归或者递推的写法来实现动态规划,其中递归写法又称记忆化搜索

11.1.2动态规划的递归写法

理解如何记录子问题的解,来避免下次遇到相同的子问题时的重复计算。
例如斐波那契数列。
递归写法:

int F(int n){
	if(n == 0 || n == 1) return 1; 
	else return F(n - 1) + F(n - 2);
}

这会有很多重复的计算。为了避免重复计算,可以开一个一维数组dp,用来保存已经计算过的结果,其中dp[n]记录结果F[n],并用dp[n] = -1来表示还没有被计算过。
可以在递归中判断dp是否是-1,如果不是1,说明已经计算过dp[n],直接返回dp[n],就是结果,否则,按照递归形式进行递归。代码如下:

const int N = 1e5 + 7;
int dp[N];
int F(int n){
	if(n == 0 || n == 1) return 1;//递归边界
	if(dp[n] != -1) return dp[n];//已经计算过,直接返回结果,不再重复计算
	else{
		dp[n] = F[n - 1] + F[n - 2];//计算F[n]保存至dp[n]
		return dp[n];//返回F[n]的结果 
	} 
}

在这里插入图片描述
在这里插入图片描述

这样就把已经计算过的内容记录了下来,于是当下次再碰到需要计算相同的内容时,就可以直接用了,这也是记忆化搜索这个名字的由来。如图,记忆化搜索把时间复杂度从O(n2)降到了O(n),也就是说用一个O(n)的空间力量就让时间复杂度降低到了线性级别。(空间换时间)

通过上面的例子可以引出一个概念:如果一个问题可以被分解成若干个子问题,且这些子问题会重复出现那就称这个问题有重叠子问题
动态规划通过记录重叠子问题的解来避免重复计算。因此,一个问题必须拥有重叠子问题,才能使用动态规划解决。

11.1.3动态规划的递推写法

以数塔问题为例。
将一些数字排成数塔状,其中第一层有一个数,第二层有两个数……第n层有n个数。现在要从第一层走到第n层,每次只能走向下一层链接的两个数字中的一个,问:最后路径上所有数字相加之后得到的最大和是多少?
在这里插入图片描述

<think>嗯,用户想找杨辉三角的递归实现方法。首先,我得回忆一下杨辉三角的结构。杨辉三角每一行的第一个最后一个数都是1,中间的数等于上一行同位置前一个位置的数之递归的话,可能需要用这个递推关系。 不过直接递归可能会有重复计算的问题,比如计算第n行的某个数,可能需要多次计算n-1行的数,效率不高。想到用户提供的参考代码里用了记忆化数组来存储已经计算过的值,这样可以避免重复递归,提高效率。这个点得在回答里强调。 用户提供的C++代码用了二维数组num来保存中间结果,递归函数Num里先检查是否已经计算过,如果计算过就直接返回,否则递归计算并存储。这样处理是正确的,应该把这个思路解释清楚。 另外用户还提到了Python的示例,虽然代码不太完整,但可能涉及格式化输出。所以在回答里可能需要比较不同语言的实现,但用户主要问的是递归实现,所以重点放在C++Python的递归方法上。 用户可能需要具体的代码示例解释,所以需要分步骤说明递归的实现方式,以及记忆化的作用。同时,要注意递归终止条件:当位置是第一个或最后一个时返回1,否则返回前一行两个数的。 还有,用户引用的代码里有模运算%998244353,可能题目要求对大数取模,但一般杨辉三角可能不需要,这里需要指出根据题目需求决定是否添加。此外,Python实现中的空格处理可能影响输出格式,需要说明如何调整空格来对齐三角形。 最后,生成相关问题时要围绕递归实现、优化方法、不同语言对比应用场景来提问,帮助用户深入理解。</think>### 杨辉三角的递归实现方法 杨辉三角的递归实现基于其数学定义:第$i$行第$j$列的值为$C(i-1, j-1)$,且满足递推关系$num[i][j] = num[i-1][j-1] + num[i-1][j]$。递归实现需注意**记忆化优化**以避免重复计算[^1]。 #### 实现步骤 1. **定义递归函数**:函数接收行号$i$列号$j$,返回对应位置的值。 2. **递归终止条件**:当$j=1$或$j=i$时返回1。 3. **记忆化存储**:使用二维数组缓存已计算的结果,避免重复递归调用。 4. **递推计算**:未缓存时递归计算$num[i][j]$的值并存储。 #### C++实现示例(含记忆化) ```cpp #include<iostream> using namespace std; int num[1501][1501]; // 记忆化数组 int Num(int i, int j) { if (j == 1 || j == i) return 1; return num[i][j] ? num[i][j] : (num[i][j] = (Num(i-1, j-1) + Num(i-1, j)) % 998244353); } int main() { int n; cin >> n; for (int i = 1; i <= n; i++) { for (int j = 1; j <= i; j++) cout << Num(i, j) << " "; cout << endl; } return 0; } ``` #### Python实现示例(含格式化) ```python def yanghui(i, j, memo={}): if (i, j) in memo: return memo[(i, j)] if j == 1 or j == i: return 1 memo[(i, j)] = yanghui(i-1, j-1, memo) + yanghui(i-1, j, memo) return memo[(i, j)] n = 5 for i in range(1, n+1): print(" "*(n-i), end="") # 对齐空格[^2] for j in range(1, i+1): print(f"{yanghui(i, j):<4}", end="") print() ``` ### 关键点说明 1. **时间复杂度**:无记忆化时为$O(2^n)$,记忆化后优化为$O(n^2)$[^1]。 2. **空间复杂度**:记忆化数组占用$O(n^2)$空间。 3. **输出对齐**:通过计算前导空格保证三角形形状(如Python示例中的`" "*(n-i)`)[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值