子序列与子串问题

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)
           
               if(word1

以上是关于子序列与子串问题的主要内容,如果未能解决你的问题,请参考以下文章

子序列与子串问题

最长公共子串与最长公共子序列

解题报告——寻找子串

数据结构开发(14):KMP 子串查找算法

子数组/子序列/子串 dp问题的总结

最长公共子序列最长重复子串