分割回文串,编辑距离,不同子序列

Posted 楠c

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分割回文串,编辑距离,不同子序列相关的知识,希望对你有一定的参考价值。

分割回文串

在这里插入图片描述

普通解法

class Solution {
private:
    //O(n^3)差点超时
    bool isPal(const string& s,int left,int right)
    {
        while(left<right)
        {
            if(s[left]!=s[right])
              return false;
            left++;
            right--;
        }
              return true;
    }
public:
    int minCut(string s) {
       int n=s.size();
       vector<int> dp(n+1,0);
       for(int i=0;i<=n;++i)
       {
           dp[i]=i-1;
       }
       for(int i=1;i<=n;++i)
       {
           for(int j=0;j<i;++j)
           {
               if(isPal(s,j,i-1))
               {
                   dp[i]=min(dp[i],dp[j]+1);
               }
           }
       }
       return dp[n];
    }
};

因为判断回文串是个O(N)的函数
在这里插入图片描述

优化时间

判断回文串也是一个动态规划问题
在这里插入图片描述
提前将它算好,需要判断的时候传入区间,直接取出结果,两个N^2的算法,时间复杂度O(N^2)

class Solution {
public:
    int minCut(string s) {
       int n=s.size();
       vector<int> dp(n+1,0);
       for(int i=0;i<=n;++i)
       {
           dp[i]=i-1;
       }
       //这个就开成大小一样,0就对应下标0,第一个元素,
       vector<vector<bool>> isPal(n,vector<bool>(n,false));
       //判断是否为回文串的动态规划
       //看两侧是否为回文串,是的话缩小两边,判断去掉两边后是否为回文串
       //所以要从后向前走
       for(int i=n-1;i>=0;--i)
       {
           for(int j=i;j<n;++j)
           {
                //j=i,即当一个字符时
                if(i==j)
                {
                  isPal[i][j]=true;
                }
                else if(i+1==j)//j+1==i时,两个字符时只要相等就是回文
                {
                   isPal[i][j]=(s[i]==s[j]); 
                }                
                else//两个字符以上
                {
                   isPal[i][j]=(s[i]==s[j])&&(isPal[i+1][j-1]);
                }
           }       
       } 
       
       //判断次数的动态规划
       for(int i=1;i<=n;++i)
       {
           for(int j=0;j<i;++j)
           {
               //是回文串,次数+1,然后和上一个的次数相比看哪个小

               //如果第j+1和i元素为回文串,才能去算第i个元素
               if(isPal[j][i-1])//因为dp多开了一个,isPal没有多开
               {
                   dp[i]=min(dp[i],dp[j]+1);
               }
           }
       }
       return dp[n];
    }
};

效率高了很多
在这里插入图片描述

编辑距离

在这里插入图片描述
画图来仔细理解一下
在这里插入图片描述

普通解法

class Solution {
public:
    int minDistance(string word1, string word2) {
        int len1=word1.size();
        int len2=word2.size();
        
        vector<vector<int>> dp(len1+1,vector<int>(len2+1,0));
        //初始化删除操作
        for(int i=0;i<=len1;++i)
        {
           dp[i][0]=i;
        }
        //初始化插入操作
        for(int i=0;i<=len2;++i)
        {
            dp[0][i]=i;
        }

        for(int i=1;i<=len1;++i)
        {
            for(int j=1;j<=len2;++j)
            {
                //插入和删除取小
                dp[i][j]=min(dp[i-1][j],dp[i][j-1])+1;
                
                //替换有两种情况
                //1.相等不用多考虑,直接用dp[i-1][j-1]的操作
                if(word1[i-1]==word2[j-1])
                {   
                    dp[i][j]=min(dp[i][j],dp[i-1][j-1]);
                }
                else//2.不相等,用dp[i-1][j-1]的操作不够,还要+1(多1步替换操作)
                {
                    dp[i][j]=min(dp[i][j],dp[i-1][j-1]+1);
                }
            }
        }

        return dp[len1][len2];
    }
};

不同子序列

在这里插入图片描述
画图仔细理解过程在这里插入图片描述

普通解法

class Solution {
public:
    /**
     * 
     * @param S string字符串 
     * @param T string字符串 
     * @return int整型
     */
    int numDistinct(string S, string T) {
        int len1=S.size();
        int len2=T.size();
        vector<vector<int>> dp(len1+1,vector<int>(len2+1,0));
        
        //即S的前i个字符和空串的子序列个数
        //空集是每个前i个字符的子集,然后空集和空集相同即初始化为1个
        for(int i=0;i<=len1;i++)
        {
         dp[i][0]=1;
        }
        //dp[0][j]呢?昏头了,S的前0个字符,即空集和前j个字符的子集,那肯定不能初始化
        for(int i=1;i<=len1;++i)
        {
            for(int j=1;j<=len2;++j)
            {
                if(S[i-1]==T[j-1])
                {
                            //不利用S[j-1]+利用S[j-1]
                    dp[i][j]=dp[i-1][j]+dp[i-1][j-1];
                }
                else
                {   //没得选,只能不利用
                    dp[i][j]=dp[i-1][j];
                }
            }
        }
        return dp[len1][len2];
    }
};

优化空间

类似于背包问题的优化空间,需要记住从后向前递推

class Solution {
public:

    int numDistinct(string S, string T) {
        int n=S.size();
        int m=T.size();
        vector<int> dp(m+1,0);
        
        dp[0]=1;
        
        for(int i=1;i<=n;++i)
        {
            //优化时类似于背包的从后往前
            for(int j=m;j>0;--j)
            {
                //相等,不利用S[j-1]+利用S[j-1]
                if(S[i-1]==T[j-1])
                {
                    dp[j]=dp[j]+dp[j-1];
                }
                /*else
                {
                    dp[j]=dp[j];
                }*/
            }
        }
        return dp[m];
    }
};

以上是关于分割回文串,编辑距离,不同子序列的主要内容,如果未能解决你的问题,请参考以下文章

子序列与子串问题

子序列与子串问题

子序列与子串问题

算法 ---- 子序列系列问题题解(子序列编辑距离回文系列问题)

算法 ---- 子序列系列问题题解(子序列编辑距离回文系列问题)

算法 ---- 子序列系列问题题解(子序列编辑距离回文系列问题)