前言
欢迎大家积极在评论区留言发表自己的看法,知无不言,言无不尽,养成每天刷题的习惯,也可以自己发布优质的解题报告,供社区一同鉴赏,吸引一波自己的核心粉丝。
今天是五月集训第二十八天:动态规划🔥🔥🔥🔥🔥
一、练习题目
二、算法思路
- 1、70. 爬楼梯:我们用 f(x)f(x) 表示爬到第 xx 级台阶的方案数,考虑最后一步可能跨了一级台阶,也可能跨了两级台阶,所以我们可以列出如下式子:
f ( x ) = f ( x − 1 ) + f ( x − 2 ) f(x) = f(x - 1) + f(x - 2) f(x)=f(x−1)+f(x−2)
它意味着爬到第 x x x级台阶的方案数是爬到第 x − 1 x - 1 x−1级台阶的方案数和爬到第 x − 2 x - 2 x−2级台阶的方案数的和。很好理解,因为每次只能爬1 级或2级,所以 f ( x ) f(x) f(x)只能从 f ( x − 1 ) f(x - 1) f(x−1)和 f ( x − 2 ) f(x - 2) f(x−2)转移过来,而这里要统计方案总数,我们就需要对这两项的贡献求和。
以上是动态规划的转移方程,下面我们来讨论边界条件。我们是从第0级开始爬的,所以从第0级爬到第0级我们可以看作只有一种方案,即 f ( 0 ) = 1 f(0) = 1 f(0)=1;从第 0 级到第 1 级也只有一种方案,即爬一级, f ( 1 ) = 1 f(1) = 1 f(1)=1。这两个作为边界条件就可以继续向后推导出第n级的正确结果。 - 2、53. 最大子数组和:动态规划转移方程如下:
f ( i ) = m a x f ( i − 1 ) + n u m s [ i ] , n u m s [ i ] f(i)=max{f(i−1)+nums[i],nums[i]} f(i)=maxf(i−1)+nums[i],nums[i] - 3、1706. 球会落何处:偷鸡了,模拟了一下,这道题用动态规划有点没看懂题解。
- 4、1420. 生成数组:困难题还是有点难度啊~
三、源码剖析
// 70. 爬楼梯
class Solution {
public:
int climbStairs(int n) {
if (n <= 2) {
return n;
}
int dp[n + 1];
dp[0] = 0;
dp[1] = 1;
dp[2] = 2; //(1)
for(int i = 3; i <= n; ++i) {
dp[i] = dp[i - 2] + dp[i - 1]; //(2)
return dp[n];
}
};
- 1、考虑边界条件;
- 2、动态规划的递推关系式。
// 53. 最大子数组和
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int dp[100001];
dp[0] = nums[0];
int ans = dp[0];
for(int i = 1; i < nums.size(); ++i) {
dp[i] = max(dp[i - 1] + nums[i], nums[i]); //(1)
ans = max(ans, dp[i]);
}
return ans;
}
};
- 1、判断dp[i - 1]对加上后一项有没有增益的效果,如果是正向的,保留并加上后一项;如果加上dp[i - 1]还不如当前遍历的数值大,那就选择另起炉灶,变成当前的数值;
- 2、把结果更新成最大值。
// 1706. 球会落何处
class Solution {
public:
vector<int> findBall(vector<vector<int>>& grid) {
int m = grid.size();
int n = grid[0].size();
vector<int> ans(n, -1);
for(int i = 0; i < n; ++i) {
int c = i; //(1)
bool block = false;
for (int j = 0; j < m; ++j) {
int c_ = c;
c += grid[j][c]; //(2)
if(c < 0 || c >= n) {
block = true;
break;
} //(3)
if(grid[j][c_] == 1 && grid[j][c] == -1) {
block = true;
break;
}
if(grid[j][c_] == -1 && grid[j][c] == 1) {
block = true;
break;
} //(4)
}
if(block) continue;
ans[i] = c;
}
return ans;
}
};
- 1、球所在的初始列;
- 2、把球移动一下,1的话右移, -1的话左移;
- 3、判断是不是在左边缘和右边缘;
- 4、这里是判断是不是在中间形成了一个V字型。
// 1420. 生成数组
- 1、