五大经典算法之三动态递归DP
2017-04-10 15:49
281 查看
五大经典算法 动态递归DP
首先需要决定存储什么历史信息,以及用什么数据结构来存储。然后最重要的就是递推公式,最后需要考虑起始条件的值。
Leetcode 139. Word Break
要求一个非空字符串s,一个非空的字符串词典,判断s能够通过空格组成一个序列是词典里的多个单词:
例如s="leetcode"
dict=["leet","code"
]
因为“leetcode”可以改成“leet code”故返回1
使用DP,我们用dp[i]表示到字符串s的第i个元素为止能不能用字典里的词表示。假设已经知道dp[0,1,,,,i-1]的结果,要求dp[i],其递推关系:
len取自[minlen,maxlen],对于i从0到s.length,都有:
dp[i+len]=1 when dp[i]=1&&wordDict.fin(s.substr(i,len))
代码:
参考:Word Break
132. Palindrome Partitioning II
要求给定一个字符串,要求分成的若干字串都是回文,求最小分串次数。
本题采用动态规划法从后往前,引出dp数组,dp[i]表示s[0...i]的最小分割次数;
dp[i]初始化为i,每一个之间切一刀,这是最大值了;
若从0到i之间存在j,0<j<i,且有s[j...i]是回文,那么此时dp[i+1]=min(dp[i1+],dp[j]+1)
故递推公式:
dp[i+1]=min(dp[i1+],dp[j]+1)
参考:132. Palindrome Partitioning II
44. Wildcard Matching
已知‘?’可以匹配任何一个字符
已知‘×’可以匹配0个或者多个任意字符
求两个字符串是否完全匹配。
类似上面的,这里引入动态规划,设dp[i][j]表示s的前i个字符与p的前j个字符的匹配情况,其递推公式:
dp[i][j]=dp[i][j-1]||dp[i-1,j] when p[j]=='*',当此星号表示0个字符时,则主要看dp[i][j-1],当星号代表字符时,则结果主要在于前面dp[i-1][j]
dp[i][j]=dp[i-1][j-1]&&(s[i]==p[j]||p[j]=='?') when p[j]!='*'
注意s的前i个字符与p的前j个字符的匹配情况,每次i+1的结果只依赖与i 与j,在程序中可以设置二重循环,则此时二维数组可以降为一维
dp[i+1]=dp[i]&&(p[j]=='?'||p[j]==s[i]) when p[j]!='*'
当p[j]=='*'时,在次情形下,可以匹配任何情况,即只要遍历dp,发现dp[i]=1,则之后的结果肯定都是1
代码如下:
bool isMatch(string s,string p){
if(s.size()<1&&p.size()<1)return 1;
int slen=s.size();int plen=p.size();
int i=0;
int num=0;
while(i<plen){if(p[i]=='*')num++;i++;}
if(plen-num>slen)return 0;
vector<bool> dp(slen+1,false);
dp[0]=true;
for(int j=0;j<plen;j++){
if(p[j]!='*'){
for(i=slen;i>=0;i--)//以为后面更新了dp[0],故不能从i=0开始
dp[i+1]=dp[i]&&(p[j]==s[i]||p[j]=='?');//此处体现i依赖与j
}
else {
i=0;
while(i<=slen&&!dp[i])i++;
for(;i<=slen;i++)dp[i]=1;
}
dp[0]=dp[0]&&(p[j]=='*');//更新dp[0],因为dp[0]表示s是空串,只有是星才匹配
}
return dp[slen];
}
首先需要决定存储什么历史信息,以及用什么数据结构来存储。然后最重要的就是递推公式,最后需要考虑起始条件的值。
Leetcode 139. Word Break
要求一个非空字符串s,一个非空的字符串词典,判断s能够通过空格组成一个序列是词典里的多个单词:
例如s="leetcode"
dict=["leet","code"
]
因为“leetcode”可以改成“leet code”故返回1
使用DP,我们用dp[i]表示到字符串s的第i个元素为止能不能用字典里的词表示。假设已经知道dp[0,1,,,,i-1]的结果,要求dp[i],其递推关系:
len取自[minlen,maxlen],对于i从0到s.length,都有:
dp[i+len]=1 when dp[i]=1&&wordDict.fin(s.substr(i,len))
代码:
//word break bool find_vector(vector<string> ss,string s){ int i=0; while(i<ss.size()){if(s.compare(ss[i])==0)return 1;i++;} return 0; } bool wordBreak(string s,vector<string>& wordDict){ if(s.size()<1)return 0; vector<bool> dp(s.length()+1,false); dp[0]=true; int min_len=INT_MAX,max_len=0; for(int i=0;i<wordDict.size();i++){if(min_len>wordDict[i].size()){min_len=wordDict[i].size();} if(max_len<wordDict[i].size()){cout<<1;max_len=wordDict[i].size();} } for(int i=0;i<s.size();i++){ if(dp[i]){for(int len=min_len;i+len<=s.size()&&len<=max_len;len++) if(find_vector(wordDict,s.substr(i,len)))dp[i+len]=1; } if(dp[s.length()])return 1; } return dp[s.length()]; }
参考:Word Break
132. Palindrome Partitioning II
要求给定一个字符串,要求分成的若干字串都是回文,求最小分串次数。
本题采用动态规划法从后往前,引出dp数组,dp[i]表示s[0...i]的最小分割次数;
dp[i]初始化为i,每一个之间切一刀,这是最大值了;
若从0到i之间存在j,0<j<i,且有s[j...i]是回文,那么此时dp[i+1]=min(dp[i1+],dp[j]+1)
故递推公式:
dp[i+1]=min(dp[i1+],dp[j]+1)
vector <vector <bool> > getdict(string s){ vector< vector<bool> > res; for(int i=0;i<s.length();i++){ vector<bool> aa; for(int j=0;j<s.length();j++){aa.push_back(0);}; res.push_back(aa); } if(s.size()<1)return res; for(int i=s.length()-1;i>=0;i--) for(int j=i;j<s.length();j++) if(s[i]==s[j]&&((j-i<2)||res[i+1][j-1]))res[i][j]=1; return res; } //判断任意字串之间是不是回文 //palindrome Partitioning11 int minCut(string s){ int len=0; if(s.length()<1)return len; vector< vector<bool> >dict=getdict(s); vector<int> dp(s.length()+1,0); dp[0]=0; for(int i=0;i<s.size();i++){ { dp[i+1]=i+1;//初始化 for(int j=0;j<=i;j++) if(dict[j][i]) dp[i+1]=min(dp[i+1],dp[j]+1); } } return dp[s.size()]-1; }
参考:132. Palindrome Partitioning II
44. Wildcard Matching
已知‘?’可以匹配任何一个字符
已知‘×’可以匹配0个或者多个任意字符
求两个字符串是否完全匹配。
类似上面的,这里引入动态规划,设dp[i][j]表示s的前i个字符与p的前j个字符的匹配情况,其递推公式:
dp[i][j]=dp[i][j-1]||dp[i-1,j] when p[j]=='*',当此星号表示0个字符时,则主要看dp[i][j-1],当星号代表字符时,则结果主要在于前面dp[i-1][j]
dp[i][j]=dp[i-1][j-1]&&(s[i]==p[j]||p[j]=='?') when p[j]!='*'
注意s的前i个字符与p的前j个字符的匹配情况,每次i+1的结果只依赖与i 与j,在程序中可以设置二重循环,则此时二维数组可以降为一维
dp[i+1]=dp[i]&&(p[j]=='?'||p[j]==s[i]) when p[j]!='*'
当p[j]=='*'时,在次情形下,可以匹配任何情况,即只要遍历dp,发现dp[i]=1,则之后的结果肯定都是1
代码如下:
bool isMatch(string s,string p){
if(s.size()<1&&p.size()<1)return 1;
int slen=s.size();int plen=p.size();
int i=0;
int num=0;
while(i<plen){if(p[i]=='*')num++;i++;}
if(plen-num>slen)return 0;
vector<bool> dp(slen+1,false);
dp[0]=true;
for(int j=0;j<plen;j++){
if(p[j]!='*'){
for(i=slen;i>=0;i--)//以为后面更新了dp[0],故不能从i=0开始
dp[i+1]=dp[i]&&(p[j]==s[i]||p[j]=='?');//此处体现i依赖与j
}
else {
i=0;
while(i<=slen&&!dp[i])i++;
for(;i<=slen;i++)dp[i]=1;
}
dp[0]=dp[0]&&(p[j]=='*');//更新dp[0],因为dp[0]表示s是空串,只有是星才匹配
}
return dp[slen];
}
相关文章推荐
- 杭电ACM OJ 1011 Starship Troopers 树的动态规划(树的dp)经典树形背包 java写的 包看懂 递归流程完全解析
- 五大经典算法一 递归与分治
- 【算法竞赛入门经典】递归结构的动态规划 例题9-10 UVa1626
- 算法系列——五大经典查找2
- 嵌套模型(DAG上的动态规划)—动态规划入门(算法经典入门)
- 算法系列15天速成——第六天 五大经典查找【下】
- 算法系列15天速成——第四天 五大经典查找【上】
- 动态规划入门(四)DP 基本思想 具体实现 经典题目 POJ1160 POJ1037
- HDOJ_杭电2084_数塔问题,经典阶段DP动态规划问题
- java经典算法_022你用递归算年龄
- java经典算法_030猴子分桃(递归求解)
- 经典算法1:递归求解汉诺塔
- 0-1背包问题经典算法(递归实现)
- 经典算法2:递归求解整数划分
- 经典算法7:动态规划之多段图
- 一个递归的经典算法
- 动态规划入门(二)DP 基本思想 具体实现 经典题目 POJ1088 POJ1163 POJ1050
- 六个经典算法研究:A*.Dijkstra.动态规划.红黑树等算法
- 算法系列15天速成——第六天 五大经典查找【下】
- C#经典算法之递归算法