动态规划
带通配符的字符串匹配
http://noi.openjudge.cn/ch0206/6252/
#include <bits/stdc++.h> using namespace std; int main(){ bool dp[30][30]={0}; dp[0][0]=1; string x,y,t=" "; cin>>x>>y; x=t+x,y=t+y; for(int i=1;i<x.size();i++){ if(x[i]=='*') dp[i][0]=1; else break; } for(int i=1;i<x.size();i++){ for(int j=1;j<y.size();j++){ if(x[i]==y[j]||x[i]=='?'){ dp[i][j]=dp[i-1][j-1]; } else if(x[i]=='*'){ if(dp[i-1][j-1]||dp[i-1][j]||dp[i][j-1]) dp[i][j]=true; else dp[i][j]=false; } else if(x[i]!=y[j]){ dp[i][j]=false; } } } if(dp[x.size()-1][y.size()-1]) cout<<"matched"; else cout<<"not matched"; }
计算字符串距离
http://noi.openjudge.cn/ch0206/2988/
#include <iostream> #include <cmath> #include <memory.h> using namespace std; int dp[1010][1010]; int fmin(int x,int y,int z){ return min(x,min(y,z)); } int main(){ int T; cin>>T; while(T--){ memset(dp,0,sizeof(dp)); string x,y; cin>>x>>y; for(int i=0;i<=x.size();i++){ dp[i][0]=i; } for(int i=0;i<=y.size();i++){ dp[0][i]=i; } for(int i=0;i<x.size();i++){ for(int j=0;j<y.size();j++){ if(x[i]==y[j]) dp[i+1][j+1]=dp[i][j]; else dp[i+1][j+1]=fmin(dp[i][j+1],dp[i+1][j],dp[i][j])+1; } } cout<<dp[x.size()][y.size()]<<endl; } }
切割回文
http://noi.openjudge.cn/ch0206/8471/
#include <iostream> #include <cmath> #include <memory.h> using namespace std; int dp[1010]; string x; bool f(int l,int r){ for(int i=l;i<=(l+r)/2;i++){ if(x[i]!=x[l+r-i]) return 0; } return 1; } int main(){ int T; cin>>T; while(T--){ int ans=1e9; memset(dp,0x3f,sizeof(dp)); cin>>x; for(int i=0;i<x.size();i++){ if(f(0,i)) dp[i]=0; else{ for(int j=i;j>=0;j--){ if(f(j,i)) dp[i]=min(dp[i],dp[j-1]+1); } } } cout<<dp[x.size()-1]<<endl; } }
补充:
11/19
程序考试,两道原题计算字符串距离、切割回文,
切割回文没打出来,非常失落,
没和一维数组联系起来,满脑子递归,
上次打出来这个题其实也是先打了递归代码,理解了之后再转dp,
dp和递归区别,在这里就是数组记录了每一次结果,后续不用计算调用之前计算好了的结果,
爬楼梯这个例子可以好好理解一下。
考试还有一个失败地方,看见做过的题净想着回忆上次怎么做的,
然后回忆不起来,裂开。其实就当成新题做就挺好,相信自己。
哦,递归方法超时了,贴一下代码,很好理解。
1 #include <iostream> 2 #include <cmath> 3 #include <memory.h> 4 using namespace std; 5 string x; 6 bool f(int l,int r){ 7 for(int i=l;i<=(l+r)/2;i++){ 8 if(x[i]!=x[l+r-i]) 9 return 0; 10 } 11 return 1; 12 } 13 int hh(int l,int r,int ans){ 14 if(f(l,r)) 15 return ans; 16 else{ 17 int mn=1e9; 18 for(int i=r;i>=l+1;i--){ 19 if(f(i,r)) 20 mn=min(mn,hh(l,i-1,ans+1)); 21 } 22 ans=mn; 23 } 24 return ans; 25 } 26 int main(){ 27 int T; 28 cin>>T; 29 while(T--){ 30 cin>>x; 31 cout<<hh(0,x.size()-1,0)<<endl; 32 } 33 }
打完力扣最长回文子串后,我觉得切割回文我打了一个假的dp,二维矩阵记录是否是回文状态都没有,我再想想。
明白了,关于判断是否是回文,应该用状态矩阵记录,不然的话,要再写一个for循环判断。。。。我失败了(noi的数据太水了!!!)
力扣最长回文子串就超时了一上午。。。。
应该是先两个for得出所有回文子串情况保存在二维数组里,然后f函数那里改成查询二维矩阵相应数值是否为1,这样f这里O(n)时间变成O(1)时间
奇怪,可能noi数据有问题,之前14s现在21s,时间上确实优化了一个for循环,上代码。
1 #include <iostream> 2 #include <cmath> 3 #include <memory.h> 4 using namespace std; 5 int dp[1010]; 6 bool f[1010][1010]; 7 string s; 8 void ff(int n){ 9 for(int i=0;i<n;i++){//长度为1和2的直接初始化 10 f[i][i]=1; 11 if(s[i]==s[i+1]) 12 f[i][i+1]=1; 13 } 14 for(int len=3;len<=n;len++){ 15 16 for(int i=0;i+len-1<n;i++){ 17 int j=i+len-1;//右边界 18 if(s[i]==s[j]&&f[i+1][j-1]){ 19 f[i][j]=1; 20 }else{ 21 f[i][j]=0; 22 } 23 } 24 } 25 } 26 int main(){ 27 int T; 28 cin>>T; 29 while(T--){ 30 int ans=1e9; 31 memset(dp,0x3f,sizeof(dp)); 32 cin>>s; 33 ff(s.size()); 34 for(int i=0;i<s.size();i++){ 35 if(f[0][i]) dp[i]=0; 36 else{ 37 for(int j=i;j>=0;j--){ 38 if(f[j][i]) 39 dp[i]=min(dp[i],dp[j-1]+1); 40 } 41 } 42 } 43 cout<<dp[s.size()-1]<<endl; 44 } 45 }