子序列与子串问题
Posted 楠c
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了子序列与子串问题相关的知识,希望对你有一定的参考价值。
目录
按照顺序看。
最长公共子序列
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
vector<vector<int>> dp(text1.size()+1,vector<int>(text2.size()+1,0));
for(int i=1;i<=text1.size();i++)
{
for(int j=1;j<=text2.size();j++)
{
if(text1[i-1]!=text2[j-1])
{
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
else
{
dp[i][j]=dp[i-1][j-1]+1;
}
}
}
return dp[text1.size()][text2.size()];
}
};
上面是返回长度,牛客上还有一道要求返回最长的那个子串。
class Solution {
public:
/**
* longest common subsequence
* @param s1 string字符串 the string
* @param s2 string字符串 the string
* @return string字符串
*/
string LCS(string s1, string s2) {
int n=s1.size();
int m=s2.size();
vector<vector<int>> dp(n+1,vector<int>(m+1,0));
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
if(s1[i-1]==s2[j-1])
{
dp[i][j]=dp[i-1][j-1]+1;
}
else
{
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
}
}
int i=s1.size();
int j=s2.size();
string ret;
while(i > 0 && j > 0)
{
//从后往前找,如果相等就--继续找
if(s1[i-1]==s2[j-1])
{
ret+=s1[i-1];
i--;
j--;
}//如果不相等,看自己是由那个推过来的
else if(dp[i-1][j]>dp[i][j-1])
{
i--;
}
else
{
j--;
}
}
reverse(ret.begin(),ret.end());
return ret.size()==0?"-1":ret;
}
};
最长连续递增子序列
class Solution {
public:
int findLengthOfLCIS(vector<int>& nums) {
if(nums.size()<=1)
return nums.size();
vector<int> dp(nums.size(),1);
int maxL=INT_MIN;
for(int i=1;i< nums.size();i++)
{
if(nums[i]>nums[i-1])
{
dp[i]=dp[i-1]+1;
}
maxL=dp[i]>maxL?dp[i]:maxL;
}
return maxL;
}
};
最长递增序列
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
if(nums.size()<=1)
{
return nums.size();
}
//下标为i时,第i个递增子序列的长度
//为1个的时候可以看做递增,初始化为1
vector<int> dp(nums.size(),1);
int maxVal=INT_MIN;
//自己不和自己比
for(int i=1;i<nums.size();i++)
{
for(int j=0;j<i;j++)
{
if(nums[i]>nums[j])
{
dp[i]=max(dp[i],dp[j]+1);
}
maxVal=dp[i]>maxVal?dp[i]:maxVal;
}
}
return maxVal;
}
};
最长连续序列
和无重复字符的最长子串相对照
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
unordered_set<int> hash(nums.begin(),nums.end());
int maxL=0;
while(!hash.empty())
{
int now=*hash.begin();//找到开始
hash.erase(now);//删除他
int l=now-1;
int r=now+1;
while(hash.find(l)!=hash.end())
{
//--去找比他小的
hash.erase(l);
l--;
}
while(hash.find(r)!=hash.end())
{
//++去找比他大的
hash.erase(r);
r++;
}
maxL=max(maxL,r-l-1);
}
return maxL;
}
};
判断子序列
普通解法
可以转换成求他们两个的最长公共子序列,然后看长度是否和s一样,一样就说明T中有完整的s.
class Solution {
public:
bool isSubsequence(string s, string t) {
int n=s.size();
int m=t.size();
vector<vector<int>> dp(n+1,vector<int>(m+1,0));
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
if(s[i-1]==t[j-1])
{
dp[i][j]=dp[i-1][j-1]+1;
}
else
{
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
}
}
return dp[n][m]==n;
}
};
优化
双指针,当他们两个相等的时候同时向后走,不相等只有T向后走继续找相等。
class Solution {
public:
bool isSubsequence(string s, string t) {
int n=s.size();
int m=t.size();
int i=0;
int j=0;
while(i<n&&j<m)
{
if(s[i]==t[j])
{
i++;
}
j++;
}
return i==n;
}
};
不同的子序列
上一遍博客
无重复字符的最长子串
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int n=s.size();
int i=0;//滑动窗口起始值
int hash[256]={0};//有空格所以不能映射26个字符的相对位置
int result=0;
for(int j=0;j<n;++j)
{
hash[s[j]]++;
while(hash[s[j]]==2)
{
hash[s[i]]--;
i++;
}
result=max(result,j-i+1);
}
return result;
}
};
最长重复数组
class Solution {
public:
int findLength(vector<int>& nums1, vector<int>& nums2) {
int n=nums1.size();
int m=nums2.size();
vector<vector<int>> dp(n+1,vector<int>(m+1,0));
int maxL=0;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
if(nums1[i-1]==nums2[j-1])
{
dp[i][j]=dp[i-1][j-1]+1;
}
maxL=max(maxL,dp[i][j]);
}
}
return maxL;
}
};
最长公共子串
和子序列不同的是,子串要求连续。牛客这道题也是要求返回最长的子串
class Solution {
public:
/**
* longest common substring
* @param str1 string字符串 the string
* @param str2 string字符串 the string
* @return string字符串
*/
string LCS(string str1, string str2) {
int n=str1.size();
int m=str2.size();
vector<vector<int>> dp(n+1,vector<int>(m+1,0));
int maxL=0;
int maxi=0;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
if(str1[i-1]==str2[j-1])
{
dp[i][j]=dp[i-1][j-1]+1;
}
if(dp[i][j]>maxL)
{
maxL=dp[i][j];
maxi=i-1;
}
}
}
return str1.substr(maxi-maxL+1,maxL);
}
};
两个字符串的删除操作
第一种方法
dp[i][j]为,以第i个元素结尾的word1,和以底j个元素结尾的word2,要达到相等,所需要删除的最小次数.
这个是两个字符串你都可以删除。开始初始化为可能操作的最大次数。即i。
然后当两个字符相等,不用删除,他就等于上一次的操作次数。
假如不相等
class Solution {
public:
int minDistance(string word1, string word2) {
int n=word1.size();
int m=word2.size();
vector<vector<int>> dp(n+1,vector<int>(m+1,0));
for(int i=0;i<=n;++i)
{
dp[i][0]=i;
}
for(int j=0;j<=m;++j)
{
dp[0][j]=j;
}
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
以上是关于子序列与子串问题的主要内容,如果未能解决你的问题,请参考以下文章