给出字符串S和T,计算S中为T的不同的子序列的个数。

一个字符串的子序列是一个由该原始字符串通过删除一些字母(也可以不删)但是不改变剩下字母的相对顺序产生的一个新字符串。如,ACE是ABCDE的一个子序列,但是AEC不是。

这里有一个例子:

S=“rabbbit”,T=“rabbit”

返回值应为3

 

初始思路

要找出子序列的个数,首先要有找出S中为T的子序列的方法。T是S的子序列,首先其每一个字母肯定会在S中出现,通过遍历T的每一个字母即可完成这个检查。而根据不能乱序的要求,下一个字母在S中出现的位置不能在上一个字母在S中出现的位置之前。由此,我们得到下面的算法:

循环遍历T

   如果当前字母在S中,而且在S中的位置大于前一个字母在S中的位置

      继续循环

   否则

      返回

循环结束

确认T为S的子序列

上面的算法用来找S中存不存在唯一的T子序列没有问题,但是如果T中的字母在S中出现多次就不靠谱了。当T中字母多次出现在S时,意味着出现了分支。如S:doggy,T:dog。当我们遍历到g字母时,其实出现了取S中两个不同g字母的分支。看到分支,我们可以想到递归:把循环遍历T的过程改为递归,每次递归调用要处理的T的位置加1,递归结束条件为走到T的结尾。经过这样变化,每次递归条件达成意味着一个子序列出现,这样也达到了我们计算子序列个数的目的。

查找子序列(T,要查找的字母在T中的位置,上一个字母在S中的位置)

   如果 要查找的字母在T中的位置 > T的长度

      子序列个数加1

      返回

   如果当前字母在S中

      循环遍历S中所有该字母的位置

         如果当前位置 <=  上一个字母在S中的位置

            继续循环

         查找子序列(T,要查找的字母在T中的位置 + 1, 当前位置)

在上面的伪代码中,我们发现判断当前字母是否在S中并获取它在S中的位置这个功能将会被频繁调用。在具体实现时,我们应该联想到使用关联容器(如map)这种查找速度比较快的数据结构(用以字母为下标的数组也可以,查找速度更快。但是需要考虑大小写字母,非英文字母等情况)。字母可以作为关联容器的key,而一个存放位置信息的序列容器(如vector)可以作为关联容器的值。在进行正式计算前,先遍历S生成这个存放信息的关联容器,这样以后我们就不再需要S本身了。最后得到代码如下:

 1 class Solution {
 2     public:
 3         int numDistinct(std::string S, std::string T)
 4         {
 5             if(T.size() >= S.size())
 6             {
 7                 if(S == T)
 8                 {
 9                     return 1;
10                 }
11                 else
12                 {
13                     return 0;
14                 }
15             }
16             
17             positionInfo_.clear();
18             count_ = 0;
19             
20             for(int i = 0; i < S.size(); ++i)
21             {
22                 if(positionInfo_.find(S[i]) == positionInfo_.end())
23                 {
24                     positionInfo_[S[i]] = {i};
25                 }
26                 else
27                 {
28                     positionInfo_[S[i]].push_back(i);
29                 }
30             }
31             
32             FindDistinct(T, 0, -1);
33             
34             return count_;
35         }
36         
37     private:
38         
39         void FindDistinct(std::string& T, int pos, int previousPosInS)
40         {
41             if(pos > T.size() - 1)
42             {
43                 ++count_;
44                 return;
45             }
46             
47             const auto iter = positionInfo_.find(T[pos]);
48             
49             for(auto posIter = iter->second.begin(); posIter != iter->second.end(); ++posIter)
50             {
51                 if(*posIter <= previousPosInS)
52                 {
53                     continue;
54                 }
55                 
56                 FindDistinct(T, pos + 1, *posIter);
57             }
58         }
59         
60         std::map<char, std::vector<int>> positionInfo_;
61         
62         int count_;
63     };
numDistinct

相关文章: