Leetcode-3 看错题目系列
最长公共子串和最长公共子序列都是非常简单的动态规划问题。
都使用dp[i][j],都是O(n^2)的时间复杂度。
第一个状态转移方程为:dp[i][j]=0; 如果s[i]!=s[j]
dp[i][j]=dp[i-1][j-1]+1,如果s[i]==s[j]
就是表示都要以i,j结尾的子串,最长的公共子串长度
第二个状态转移方程,dp[i][j]表示无限制的子序列最长长度
如果s[i]==s[j],dp[i][j]=dp[i-1][j-1]+1
否则就继承前面,dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
傻逼了,就是一道滑动窗口傻逼题。
不过这题还是有独到之处的,那就是字符不是简单的小写英文字母,而是可以是任意字符
,这就使得我第一次写的时候overflow了。
让后才回忆起来一个知识:C语言中,char转int输出的时候,直接输出的是asc2值。
顺便过了几个月第一次再做这个傻逼题的时候还做错了
class Solution { public: unordered_map<char,int>mp; int id_cnt=0; int getid(const char &c) { if(!mp.count(c)) { mp[c]=id_cnt++; } return mp[c]; } int lengthOfLongestSubstring(string s) { if(s=="")return 0; int res=1;//显然答案的最小值为1 bool vis[130]; memset(vis,false,sizeof(vis)); int len=s.length(); int l=0,r=1; vis[getid(s[l])]=true; while(l<len&&r<len) { int x=getid(s[r]); if(vis[x])//如果右边新加上来的这个东西会破坏原来的结构 { //那么解决办法是l指针一直往右,直到消去 while(l<len) { if(getid(s[l])==x)//说明当前指向就是r指向的值 { l++; break; } l++; } r++; //冲突了必然不可能有答案更新 } else { vis[x]=true; res=max(res,r-l+1); r++; } } return res; } };
不过事实也说明leetcode是可以自己加函数的。
不过问题的关键不在这里,而是
"tmmzuxt"输出4,预期结果为5
原因是左指针移动时没有消去原来的vis,本质上还是滑动窗口不熟练
AC代码
#include<bits/stdc++.h> using namespace std; class Solution { public: unordered_map<char,int>mp; int id_cnt=0; int getid(const char &c) { if(!mp.count(c)) { mp[c]=id_cnt++; } return mp[c]; } int lengthOfLongestSubstring(string s) { if(s=="")return 0; int res=1;//显然答案的最小值为1 bool vis[130]; memset(vis,false,sizeof(vis)); int len=s.length(); int l=0,r=1; vis[getid(s[l])]=true; while(l<len&&r<len) { int x=getid(s[r]); if(vis[x])//如果右边新加上来的这个东西会破坏原来的结构 { //那么解决办法是l指针一直往右,直到消去 while(l<len) { if(getid(s[l])==x)//说明当前指向就是r指向的值 { l++; break; } vis[getid(s[l])]=false; l++; } r++; //冲突了必然不可能有答案更新 } else { vis[x]=true; res=max(res,r-l+1); r++; } } return res; } }; int main() { Solution s; cout<<s.lengthOfLongestSubstring("tmmzuxt")<<endl; return 0; }