zoukankan      html  css  js  c++  java
  • leetcode 730 Count Different Palindromic Subsequences

    题目链接:

    https://leetcode.com/problems/count-different-palindromic-subsequences/description/

    730.Count Different Palindromic Subsequences

    题意

    给你一个只包含a、b、c、d字符的字符串,总共有多少个不重复的回文子序列。

    题解

    容易想到这题可以用动态规划的方法来解决。
    1、dp[l][r][k]表示区间[l,r]内,以字符k+'a'结尾的回文子序列个数。
    当k+'a'S[l]S[r]的时候,我们考虑两种情况:
    1)、l,r不加进来:dp[l+1][r-1][k],k'属于[0,3];
    2)、l,r加进来:sigma(dp[l+1][r-1][k'])+2,其中0<=k'<=3。
    由于要考虑不重复,经过观察容易发现第1)种情况恰好会被第2)种情况所包含,所以我们可以得出最终结论:dp[l][r][k]=sigma(dp[l+1][r-][k']+2),0<=k'<=3。(具体的转移代码中体现)

    const int mod=1e9+7;
    class Solution {
    public:
        int dfs(int l,int r,int k,string& S,vector<vector<vector<int> > >& dp) {
            if(r<l) return 0;
            if(l==r) return (k==S[l]-'a')?1:0;
            if(dp[l][r][k]>=0) return dp[l][r][k];
            int& res=dp[l][r][k]=0;
            if(r-l==1) {
                if(S[l]==S[r]&&k==S[l]-'a') return res=2;
                if(k==S[l]-'a'||k==S[r]-'a') return res=1;
                return res=0;
            }
            if(S[l]==S[r]&&S[l]-'a'==k) {
                res=2;
                for(int i=0; i<4; i++) {
                    res+=dfs(l+1,r-1,i,S,dp);
                    res%=mod;
                }
            } else {
                if(S[l]-'a'==k){
                    res=dfs(l,r-1,k,S,dp);
                }else{
                    res=dfs(l+1,r,k,S,dp);
                }
            }
            return res;
        }
    
        int countPalindromicSubsequences(string S) {
            int n=S.length();
            vector<vector<vector<int> > > dp(n,vector<vector<int> >(n,vector<int>(4,-1)));
    
            int ans=0;
            for(int i=0; i<4; i++) {
                ans+=dfs(0,n-1,i,S,dp);
                ans%=mod;
            }
    
            return ans;
    
        }
    };  
    

    2、dp[l][r]表示子串[l,r]中的不重复回文子序列,则容易得到转移方程dp[l][r]=sigma(dp[l[k']+1][r[k']-1]+l[k']==r[k']?1:2),其中0<=k'<=3。并且l[k']代表从l(包括l自己)往右第一个为k'+'a'的字符,r[k']代表从r(包括r自己)往左第一个为k'+'a'的字符。

    const int mod=1e9+7;
    typedef long long LL;
    class Solution {
    public:
        int dfs(int l,int r,string& S,vector<vector<LL> >& dp) {
            if(l>r) return 0;
            if(dp[l][r]>=0) return dp[l][r];
            LL& res=dp[l][r]=0;
            for(int i=0;i<4;i++){
                int lef=nxt[l][i],rig=pre[r][i];
                if(lef>rig) continue;
                if(S[lef]==S[rig]){
                    res++;
                    if(lef<rig) res++;
                }
                res+=dfs(lef+1,rig-1,S,dp);
                res%=mod;
            }
            return res;
        }
    
        void init(int n,string& S){
            int pos[4];
            memset(pos,-1,sizeof(pos));
            for(int i=0;i<n;i++){
                pos[S[i]-'a']=i;
                for(int j=0;j<4;j++){
                    pre[i][j]=pos[j];
                }
    
            }
            for(int i=0;i<4;i++) pos[i]=n;
            for(int i=n-1;i>=0;i--){
                pos[S[i]-'a']=i;
                for(int j=0;j<4;j++){
                    nxt[i][j]=pos[j];
                }
    
            }
        }
    
        int countPalindromicSubsequences(string S) {
            int n=S.length();
            init(n,S);
            vector<vector<LL> > dp(n,vector<LL>(n,-1));
            return dfs(0,n-1,S,dp);
        }
    private:
        int nxt[1001][4],pre[1001][4];
    };
  • 相关阅读:
    组合数学——cf893E
    前缀和+贪心+线段树——cf893D
    期望线性性+线段树双tag标记——cf895E
    状压dp+数论——cf895C好题!
    官方资料&一些好的博客与技术点
    批处理小技巧总结
    使用 SP_OAXXX 创建文件夹,注意区别于 xp_cmdshell --mkdir xxx
    第一次使用并配置Hibernate
    做一个有心人
    强说愁
  • 原文地址:https://www.cnblogs.com/fenice/p/7979770.html
Copyright © 2011-2022 走看看