概述
只要按照学习的时间统计天数就保证是连续学习的欺诈术…
目录
- 1.算法入门_动态规划
- 1.1 跳台阶
- 1.2 最长公共子串
- 1.3 矩阵的最小路径和
- 1.4 接雨水问题
1.算法入门_动态规划
1.1 跳台阶
参考:跳台阶|官方|精华题解
题解没问题,3种方法都很好。
法一:递归
有的时候正着枚举有很多,但是倒着推,就发现只有2种情况。
class Solution {
public:
int jumpFloor(int number) {
if(number<=1) return 1;
return jumpFloor(number-1)+jumpFloor(number-2);
}
};
法二:记忆化搜索
先从上向下递归,再从下向上回溯。
如果有重复递归,就直接调用结果。
class Solution {
public:
int jumpFloor(int number) {
int f[50]{0};//注意初始化方法
if(number<=1) return 1;
if(f[number]>0) return f[number];
return jumpFloor(number-1)+jumpFloor(number-2);
}
};
法三:动态规划
直接从下向上累加。
但核心还是要先确定每个动态转移方程:f[i]=f[i-1]+f[i-2]
class Solution {
public:
int dp[50]{0};
int jumpFloor(int number) {
dp[0]=1,dp[1]=1;
for(int i=2;i<=number;i++)
{
dp[i]=dp[i-1]+dp[i-2];
}
return dp[number];
}
};
1.2 最长公共子串
参考:【数据结构和算法】动态规划解最长公共子串
突然发现动态规划用矩阵的话,那么状态转移方程一定会涉及到2个维度的量,在这道题一样的,是一个变形的向右向下查找问题。
主要思路:
dp
矩阵的每个元素代表2个string
分别在第i
、j
个元素结尾的时候公共子串的长度。转移方程:dp[i][j]=dp[i-1][j-1]+1
。省去初始化赋0,同时更直观代表元素位置,dp
2个维度分别多1。
class Solution {
public:
/**
* longest common substring
* @param str1 string字符串 the string
* @param str2 string字符串 the string
* @return string字符串
*/
string LCS(string str1, string str2) {
// write code here
//int index,mmax;
int m = str1.size(), n = str2.size();
vector<vector<int>> dp(m + 1, vector<int> (n + 1, 0));
int index, len = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (str1[i] == str2[j]) {
dp[i + 1][j + 1] = dp[i][j] + 1;
if (dp[i + 1][j + 1] > len) {
len = dp[i + 1][j + 1];
index = i;
}
}
}
}
string str;
str.assign(str1,index-len+1,len);
return str;
}
};
1.3 矩阵的最小路径和
大佬给出递归和动态规划2种思路。
参考:题解 | #矩阵的最小路径和#
动态规划核心还是确定动态转移方程。
这里可以想到,每一处的最短路径,是上面或者左边的最短路径+当前元素路径长。
那么就可以构建dp[i][j]=min(dp[i-1][j],dp[i][j-1])+matrix[i][j]
。
第二大问题是初始化。
为什么要初始化,可以这样想:当我要确定第[i][j]
个位置的最短路径时,要不然就要找它上面的,要不然就找左边的最短路径,那么极端情况就是最上一行和最左一列,因此需要首先初始化这2部分。而最上一行的上一步只能是左边路径,最左一列的上一步只能是上边路径。所以分别构建dp[0][j]=dp[0][j-1]+matrix[i][j]
和dp[i][0]=dp[i-1][0]+matrix[i][j]
。而这两者最终都会追溯到起始点dp[0][0]
,所以这个也要初始化。
INT_MAX = 2^31 -1,INT_MIN= -2^31
class Solution {
public:
/**
*
* @param matrix int整型vector<vector<>> the matrix
* @return int整型
*/
int minPathSum(vector<vector<int> >& matrix) {
// write code here
int r = matrix.size(), c = matrix[0].size(); //取行和列
vector<vector<int>> dp(r, vector<int> (c));
//初始化,需要确定左上,最上行,最左列
dp[0][0] = matrix[0][0];
for (int i = 1; i < c; i++) {//初始化最上行
dp[0][i] = dp[0][i - 1] + matrix[0][i];
}
for (int j = 1; j < r; j++) {
dp[j][0] = dp[j - 1][0] + matrix[j][0];
}
for (int i = 1; i < r; i++) {
for (int j = 1; j < c; j++) {
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + matrix[i][j];
}
}
return dp[r-1][c-1];
}
};
大佬的优化,先搬运,再解读。
来解读了,主要是考虑到不往回走,所以每一处的值是可以被重新覆盖的。
# 搬运代码
class Solution {
public:
/**
*
* @param matrix int整型vector<vector<>> the matrix
* @return int整型
*/
int minPathSum(vector<vector<int> >& matrix) {
int row = matrix.size(), col = matrix[0].size();
for (int i = 0; i < row; i ++) {
for (int j = 0; j < col; j ++) {
if (i == 0 && j != 0) { // 数组第一行
matrix[0][j] += matrix[0][j - 1];
} else if (j == 0 && i != 0) { // 数组第一列
matrix[i][0] += matrix[i - 1][0];
} else if (i > 0 && j > 0) {
// 两种方式取最小的
matrix[i][j] += min(matrix[i - 1][j], matrix[i][j - 1]);
}
}
}
return matrix[row - 1][col - 1];
}
};
1.4 接雨水问题
三指针目前最清晰。
参考:【数据结构和算法】双指针求接雨水问题,图文结合
class Solution {
public:
/**
* max water
* @param arr int整型vector the array
* @return long长整型
*/
long long maxWater(vector<int>& arr) {
// write code here
int s = arr.size();
if (s <= 2) return 0;
int left = 0, right = s - 1, mid, high = 0;
//bool judge=true;
long long rain = 0;
for (int i = 0; i < s; i++) {
if(arr[i]>high)
{
high=arr[i];
mid=i;
}
}
for (int i = left + 1; i < mid; i++) {
if (arr[i] < arr[left]) rain += (arr[left] - arr[i]);
else
left = i;
}
for (int i = right - 1; i > mid; i--) {
if (arr[i] < arr[right]) rain += (arr[right] - arr[i]);
else
right = i;
}
return rain;
}
};
双指针暂时理解不到位。
最后
以上就是幸福大炮为你收集整理的[学习笔记-C++篇]day21 动态规划1.算法入门_动态规划的全部内容,希望文章能够帮你解决[学习笔记-C++篇]day21 动态规划1.算法入门_动态规划所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复