lintcode 734. 形式为a^i b^j c^k的子序列数量 题解

Posted J1ac

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了lintcode 734. 形式为a^i b^j c^k的子序列数量 题解相关的知识,希望对你有一定的参考价值。

描述

给一字符串, 对形式为 a^i b^j c^k 的子序列进行计数, 即它由 i 个字符 a, 接着是 j 个字符 b, 然后是 k 个字符 c组成, i >= 1, j >= 1, k >= 1.
Note: 如果两个子序列在原字符串中的index集合是不同的,则认为两个子序列不同。

样例

给定 s = abbc, 返回 3 子序列为 abcabc 和 abbc
给定 s = abcabc, 返回 7 子序列为 abcabcabbcaabcabccabc 和 abc

 
思路:这道题相当于一道排列组合题,最自然的想法是暴力搜索,以a->b->c的顺序从先往后搜索,维护一个结果总数。提交结果也可想而知,TLE,大数据量没能通过。
  转头一想就能知道这种题应该用动态规划,于是解也就出来了,这里贴出两种思路的代码:
 
第一种思路是从前往后搜索(TLE):
class Solution {
public:
    /**
     * @param source: the input string
     * @return: the number of subsequences 
     */
    int countSubsequences(string &source) {
        // write your code here
        findPath(source,0,\0);
        return res;
    }

    void findPath(string & source, int index, char c){
        if(c == \0){
            for(int i = index; i < source.size(); ++i){
                if(source[i] == a) findPath(source,i+1,a);
            }
        }else if(c == a || c == b){
            for(int i = index; i < source.size(); ++i){
                if(source[i] == c) findPath(source,i+1,c);
            }
            for(int i = index; i < source.size(); ++i){
                if(source[i] == c+1) {
                    if(c == b) ++res;          //b之后碰到第一个c,结果+1
                    findPath(source,i+1,c+1);
                }
            }
        }else if(c == c){
            for(int i = index; i < source.size(); ++i){
                if(source[i] == c) {
                    findPath(source,i+1,c);
                    ++res;                  //连续的c,结果+1
                }
            }
        }
    }
    
private:
    int res = 0;
};

第二种思路是动态规划,其中DPA,DPB,DPC分别表示到当前坐标为止,以‘a‘、‘b‘、‘c‘结尾的符合要求的前缀一共有几个。

递推式为:DPX[i] = DP(X-1)[i-1] + 2*DPX[i-1]。即从上一个字母第一次变成当前字母的数量加上以当前字母结尾的数量乘2(当前字母可取,可不取)。

时间复杂度O(n),空间复杂度O(n)。

class Solution {
public:
    /**
     * @param source: the input string
     * @return: the number of subsequences 
     */
    int countSubsequences(string &source) {
        // write your code here
        int size = source.size();
        if(size < 3) return 0;
        vector<int> DPA(size,0);
        vector<int> DPB(size,0);
        vector<int> DPC(size,0);
        
        if(source[0] == a) DPA[0] = 1;
        for(int i = 1; i < size; ++i){
            if(source[i] == a){
                DPA[i] = 2*DPA[i-1] + 1;
                DPB[i] = DPB[i-1];      //注意三个列表的同步
                DPC[i] = DPC[i-1];
            }else if(source[i] == b){
                DPA[i] = DPA[i-1];
                DPB[i] = DPA[i-1] + DPB[i-1]*2;
                DPC[i] = DPC[i-1];
            }else if(source[i] == c){
                DPA[i] = DPA[i-1];
                DPB[i] = DPB[i-1];
                DPC[i] = DPB[i-1] + DPC[i-1]*2;
            }else{
                continue;
            }
        }
        return DPC[size-1];
    }

};

 

以上是关于lintcode 734. 形式为a^i b^j c^k的子序列数量 题解的主要内容,如果未能解决你的问题,请参考以下文章

LintCode 819. 单词排序

#734 (Div. 3) 1551 E. Fixed Points(简单dp)

LintCode 463 Sort Integer

lintcode-medium-The Smallest Difference

CodeForces 734F Anton and School

LintCode刷题——最大正方形