<Leetcode>Distinct Subsequences

来源:互联网 发布:淘宝进店自动打招呼 编辑:程序博客网 时间:2024/06/11 12:46

Given a string S and a string T, count the number of distinct subsequences of T in S.

A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, "ACE" is a subsequence of "ABCDE" while "AEC" is not).

Here is an example:
S "rabbbit"T "rabbit"

Return 3.

链接:http://oj.leetcode.com/problems/distinct-subsequences/

    第一遍直接用的傻逼搜索,给TLE跪,只能继续想办法。

       发现貌似可以用DP做,对于模板串,可以分别计算出其长度为1、2、...len的尾串,累加可得结果。

想降低时间复杂度,于是用了很复杂的数据结构,先进行预处理,对于模板串的每个字母Ct,计算出它所能代表的字串长度,比如abba中,a的字串长度可能有2种:1和4,b的长度可能有2种:2和3。然后对于源串S,从后向前对每个字母进行初始化,每个S中的字符都有一个桶结构去维护其各种字串长度信息,各子串信息存在结点中,记录累加值acc和位置(模板串T中的)pos值(pos和子串长度一一对应,记录pos即可)。预处理复杂度为O(S.length)。

       之后便是从后向前累加,动态规划,时间复杂度O(S.length * avg(bucketLength)), avg(bucketLength)是T中各字符出现重复次数的平均值。

       Dp中使用了一个lastpos数组,对每个已出现字符的上一次进行记录以避免每次都要查找。对S从后向前分别进行计算,对出现在i位置的字符Ci,扫描其桶,在桶中取j结点,根据结点信息中的pos值(T中出现位置)和T.length可算出该子串长度,获取该长度子串的acc值a1,以及该长度-1的子串的acc值a2,若子串长度为1,新的acc值为a1+1,否则,acc值为a1+a2。(acc为从后往前的累加值,取a1是因为在该字符之后的位置已经存在该字符表示的该长度的子串了,需要将它的值算进来,取a2是因为该字符加上其后比其长度小1的子串的累加值即为该长度的子串数目)。

       独立解决这种题目还是很费劲的,如果能早几个月开始准备就好了,那数据结构写得略崩溃。做这个题花了我一下午加半个晚上,妹的,和PAT的某题有点像,都是复杂的数据结构,会搞死~~~以后做这种复杂题,不要急着写代码,先把推倒想清楚,数据结构设计好,免得写了一半发现不对之类的。

#include<iostream>#include<string>#include<memory>#include<assert.h>using namespace std;#define S_MAX_LEN1000#define T_MAX_LEN50class Node{public:int pos;int acc;};class NodeBucket{public:int len;Node *node[32];NodeBucket():len(0){}NodeBucket &operator=(const NodeBucket &m){len = m.len;for(int i=0;i<len;i++)this->node[i] = m.node[i];return *this;}};class Solution{public:string DropTheSource(const string &s,const string &t){bool v[256];string sRet;char buf[S_MAX_LEN];int len=0;memset(v,0,sizeof(v));for(int i=0;i<sLen;i++)v[s[i]]=true;for(int i=0;i<tLen;i++)if(!v[t[i]])return sRet;memset(v,0,sizeof(v));for(int i=0;i<tLen;i++)v[t[i]]=true;for(int i=0;i<sLen;i++)if(v[s[i]])buf[len++] = s[i];buf[len] = '\0';sRet = buf;return sRet;}void init1(const string &s,const string &t){NodeBucket* m[256];memset(m,0,sizeof(m));//scan the template str for making NodeBucket by character.for(int i=0;i<tLen;i++){if(m[t[i]]==NULL){m[t[i]] = &nodeBucketPool[nbpLen++];m[t[i]]->len=0;}Node* ptmp = &nodepool[npLen++];ptmp->acc=0;ptmp->pos = i;m[t[i]]->node[ m[t[i]]->len++ ] = ptmp;}//scan the source str and append the NodeBucketfor(int i=0;i<sLen;i++){nodeBucketPool[nbpLen] = *m[s[i]];nodeBucket[i] = &nodeBucketPool[nbpLen++];}return;}inline int Get_Acc_of_Sub_Str_In_Temp(int Last_Pos[],const string &t,int len){//get the acc of the char of substr with length len in the SourceStrif(len<1)return 0;int pos = Last_Pos[ t[tLen-len] ];if(pos==-1)return 0;int pos1 = tLen - len;for(int i=0;i<nodeBucket[pos]->len;i++)if(nodeBucket[pos]->node[i]->pos == pos1)return nodeBucket[pos]->node[i]->acc;assert(false);return -1;}int Dp(const string &s,const string &t){int T_last_pos[256],length,tmp1,tmp2;memset(T_last_pos,-1,sizeof(T_last_pos));for(int i=sLen-1;i>=0;i--){for(int j=0;j<nodeBucket[i]->len;j++){length = tLen - nodeBucket[i]->node[j]->pos;//the length of the substrtmp1 = Get_Acc_of_Sub_Str_In_Temp(T_last_pos,t,length);if(length==1)nodeBucket[i]->node[j]->acc = tmp1+1;else{tmp2 = Get_Acc_of_Sub_Str_In_Temp(T_last_pos,t,length-1);nodeBucket[i]->node[j]->acc = tmp1 + tmp2;}}T_last_pos[s[i]] = i;}return Get_Acc_of_Sub_Str_In_Temp(T_last_pos,t,tLen);}int numDistinct(string S, string T){int ret;npLen = nbpLen = 0;sLen = S.length(); tLen = T.length();//1.Drop the character from the source string which is excluded by the template string.string s = DropTheSource(S,T);sLen = s.length();if(sLen==0)return 0;//2.Load the nodeBucket array.init1(s,T);//3.Calculate the nodeBucket by DP.ret = Dp(s,T);return ret;}int sLen,tLen;Node nodepool[5*T_MAX_LEN];int npLen;NodeBucket nodeBucketPool[S_MAX_LEN + T_MAX_LEN];int nbpLen;NodeBucket *nodeBucket[S_MAX_LEN];};int main(){string a,b;while(cin>>a>>b){Solution s;cout<<s.numDistinct(a,b)<<endl;}return 0;}