子序列与子串问题

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)
           以上是关于子序列与子串问题的主要内容,如果未能解决你的问题,请参考以下文章

子序列与子串问题

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

79 最长公共子串

计蒜客课程竞赛入门--最长上升子序列(LIS) 流程记

Educational CF # 17 C 二分,字符串 D 最长路,dp

动态规划_公共最长子序列 java