牛客网算法学习笔记-动态规划(2)
来源:互联网 发布:淘宝望远镜 编辑:程序博客网 时间:2024/05/20 16:33
案例一 台阶问题
题目:有n级台阶,一个人每次上一级或者两级,问有多少种走完n级台阶的方法。为了防止溢出,请将结果Mod 1000000007
给定一个正整数int n,请返回一个数,代表上楼的方式数。保证n小于等于100000。
暴力搜索方法:
假设第i层台阶的方法数为f(i),则f(i)=f(i-1)+f(i-2),第i层只能等于i-1层上一阶加上i-2层上两阶,因此:
f(1)=1
f(2)=2
f(i)=f(i-1)+f(i-2)
代码如下:
class GoUpstairs {
public:
int countWays(int n) {
if(n<1)
return 0;
if(n==1||n==2)
return n;
return countWays(n-1)+countWays(n-2);
}
};
动态规划方法:
根据f(i)=f(i-1)+f(i-2)直接写出即可:
class GoUpstairs {
public:
int countWays(int n) {
if(n<1) return 0;
if(n==1||n==2)
return n;
int res[n+1];
res[1]=1;
res[2]=2;
for(int i=3;i<=n;i++)
res[i]=(res[i-1]+res[i-2])%1000000007;
return res[n];
}
};
案例二 矩阵最小路径和
题目:
有一个矩阵map,它每个格子有一个权值。从左上角的格子开始每次只能向右或者向下走,最后到达右下角的位置,路径上所有的数字累加起来就是路径和,返回所有的路径中最小的路径和。
给定一个矩阵map及它的行数n和列数m,请返回最小路径和。保证行列数均小于等于100
动态规划方法:建立一个与矩阵map一样大的矩阵dp[n][m],其中dp[i][j]表示到达位置(i,j)的最小路径之和。
dp[0][0]=map[0][0] //这个不用解释了吧
dp[0][j]=map[0][j]+map[0][j-1] 0<j<=m-1 //沿着第一行走,最短路径只能是累加
dp[i][0]=map[i][0]+map[i-1][0] 0<i<=n-1 //沿着第一列走,最短路径只能是累加
dp[i][j]=min(dp[i-1][j],dp[i][j-1])+map[i][j] 1<=i<=n-1,1<=j<=m-1 //其余的位置(i,j),只能从他上面的位置(i-1,j)或者是他左边的位置(i,j-1)走过来,所以选其中最小的加上现在位置的值就是该位置的最小路径和
class MinimumPath {
public:
int getMin(vector<vector<int> > map, int n, int m) {
vector<vector<int> > res;
res.resize(n);
for (int i = 0; i < n; ++i){
res[i].resize(m);
}
res[0][0]=map[0][0];
for(int i=1;i<n;i++)
res[i][0]=res[i-1][0]+map[i][0];
for(int j=1;j<m;j++)
res[0][j]=res[0][j-1]+map[0][j];
for(int i=1;i<n;i++)
for(int j=1;j<m;j++)
res[i][j]=min(res[i-1][j],res[i][j-1])+map[i][j];
return res[n-1][m-1];
}
};
案例三 最长上升子序列问题
题目:这是一个经典的LIS(即最长上升子序列)问题,请设计一个尽量优的解法求出序列的最长上升子序列的长度。
给定一个序列A及它的长度n(长度小于等于500),请返回LIS的长度。
思路:申请一个dp[n],dp[i]的含义为:以A[i]这个数结尾的情况下,A[0,...,i]中的最大递增子序列的长度
dp[i]=max{dp[j]+1, 0<=j<i, A[j]<A[i]}
class LongestIncreasingSubsequence {
public:
int getLIS(vector<int> A, int n) {
int dp[n];
dp[0]=1;
int res=0;
for(int i=1;i<n;i++){
int max=0;
for(int j=0;j<i;j++){
if(A[i]>A[j]&&max<dp[j])
max=dp[j];
}
dp[i]=max+1;
}
for(int i=0;i<n;i++)
res=res>dp[i]?res:dp[i];
return res;
}
};
案例四 最长公共子序列问题
题目:给定两个字符串A和B,返回两个字符串的最长公共子序列的长度。例如,A="1A2C3D4B56”,B="B1D23CA45B6A”,”123456"或者"12C4B6"都是最长公共子序列。
给定两个字符串A和B,同时给定两个串的长度n和m,请返回最长公共子序列的长度。保证两串长度均小于等于300。
思路:建立一个大小为n*m的矩阵dp,dp[i][j]的含义是:字符串A[0,...,i]与B[0,...,j]的最长公共子序列的长度,那么
1. dp的第一列为dp[i][0],代表A[0,...,i]与B[0]之间的最长公共子序列,假设A[i]==B[0],那么dp[i][0]=1,且dp[i,...n-1][0]=1
2. dp的第一行为dp[0][j],代表A[0]与B[0,...,j]之间的最长公共子序列,假设A[0]==B[j],那么dp[0][j]=1,且dp[0][j,...m-1]=1
3. dp[i][j]的值分为以下两种情况:
dp[i][j]=max(dp[i-1][j],dp[i][j-1]) //当A[i]!=B[j]的时候
dp[i][j]=dp[i-1][j-1]+1 //当A[i]==B[j]的时候
class LCS {
public:
int findLCS(string A, int n, string B, int m) {
int dp[n+1][m+1];
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
if(A[i]!=B[j])
dp[i+1][j+1]=max(dp[i][j+1],dp[i+1][j]);
else
dp[i+1][j+1]=dp[i][j]+1;
}
return dp[n][m];
}
};
案例五 背包问题
题目:一个背包有一定的承重cap,有N件物品,每件都有自己的价值,记录在数组v中,也都有自己的重量,记录在数组w中,每件物品只能选择要装入背包还是不装入背包,要求在不超过背包承重的前提下,选出物品的总价值最大。
给定物品的重量w价值v及物品数n和承重cap。请返回最大总价值。
思路:申请一个大小为N*W的矩阵dp,dp[i][j]表示当重量不超过j时前i件物品的最大值,他有两种情况:
1. 第i件物品确定装入背包,那么前i-1个物品的重量不能超过j-w[i],此时dp[i][j]=dp[i-1][j-w[i]+v[i]
2. 第i件物品不装入背包,那么前i-1个物品的重量不超过j即可,此时dp[i][j]=dp[i-1][j]
dp[i][j]就取二者中的最大值即可
class Backpack {
public:
int maxValue(vector<int> w, vector<int> v, int n, int cap) {
int dp[n+1][cap+1];
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
for(int j=1;j<=cap;j++){
if(j>=w[i-1])
dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i-1]]+v[i-1]);
else
dp[i][j]=dp[i-1][j];
}
return dp[n][cap];
}
};
案例六 最优编辑问题
题目:对于两个字符串A和B,我们需要进行插入、删除和修改操作将A串变为B串,定义c0,c1,c2分别为三种操作的代价,请设计一个高效算法,求出将A串变为B串所需要的最少代价。
给定两个字符串A和B,及它们的长度和三种操作代价,请返回将A串变为B串所需要的最小代价。保证两串长度均小于等于300,且三种代价值均小于等于100。
思路:假设A,B的长度分布为N和M,那么建立一个大小为(N+1)*(M+1)的矩阵dp,其中dp[i][j]表示的含义是将A[0,...,i-1]编辑成B[0,...,j-1]的最小代价
dp[0][0]=0
dp[i][0]=c1*i
dp[0][j]=c0*i
dp[i][j]有四种情况分别如下:
1. dp[i][j]=dp[i-1][j]+c1
2. dp[i][j]=dp[i][j-1] +c2
3. 当A[i-1]==B[j-1]时,dp[i][j]=dp[i-1][j-1]
4. 当A[i-1]!=B[j-1]时,dp[i][j]=dp[i-1][j-1] +c2
class MinCost {
public:
int findMinCost(string A, int n, string B, int m, int c0, int c1, int c2) {
int dp[n+1][m+1];
dp[0][0]=0;
for(int i=1;i<=n;i++)
dp[i][0]=i*c1;
for(int j=1;j<=m;j++)
dp[0][j]=j*c0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
int temp=min(dp[i-1][j]+c1,dp[i][j-1]+c0);
if(A[i-1]==B[j-1]){
dp[i][j]=min(temp,dp[i-1][j-1]);
}
else
dp[i][j]=min(temp,dp[i-1][j-1]+c2);
}
return dp[n][m];
}
};
以上就是一些经典动态规划算法的学习笔记,如果有问题请各位指正,多多交流!
- 牛客网算法学习笔记-动态规划(2)
- 动态规划(算法导论学习笔记)
- 牛客网算法学习笔记-动态规划(1)
- 【算法学习笔记】-动态规划
- 算法学习(2):动态规划
- 基础算法学习笔记(二)----动态规划
- 算法导论学习笔记(十一):动态规划(一)
- 【算法学习笔记】之动态规划
- 动态规划与贪婪算法学习笔记
- 算法学习笔记--动态规划(1)
- 算法导论学习笔记----动态规划
- 动态规划(学习笔记)
- 动态规划算法笔记
- 【算法】动态规划笔记
- 算法学习-(二)动态规划算法
- 动态规划算法学习
- 算法学习--动态规划
- 动态规划算法学习
- bootstrap汉堡按钮
- 使用ItemTouchHelper拖拽时两个item跟着动解决方法
- Android开源二维码识别项目zxing横屏改为竖屏识别解决方案
- 《深入探索C++对象模型》第二章:构造函数语意学(上)
- OpenGL入门学习
- 牛客网算法学习笔记-动态规划(2)
- MyEclipse+Tomcat+MAVEN+SVN项目完整环境搭建
- C# ajax 大文件上传
- 视频质量分析指标分析------以ClearView为例
- 窗体部件效果之阴影
- 简单MediaPlayer 例子
- FFmpeg工具安装以及使用(Windows)
- 得到控制台窗口的句柄
- CSS之background-origin属性