Leetcode | Distinct Subsequences

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.

题意有点歧义。其实是要求S中有多少个不同的子串等于T。

dfs的思路很好写,就是从s查到*t,如果找到了,再从s+1中去找*(t+1),直到最后t为空。

 1 class Solution {
 2 public:
 3     int numDistinct(string S, string T) {
 4         count = 0;
 5         dfs(S.c_str(), T.c_str());
 6         return count;
 7     }
 8     
 9     void dfs(const char* s, const char* t) {
10         if (*s == '') return;
11         if (*t == '') {
12             count++;
13             return;
14         }
15         const char* p = s-1;
16         while ((p = strchr(p+1, *t)) != NULL) {
17             dfs(p, t+1);
18         }
19     }
20 private:
21     int count;
22 };

dfs对大数据会超时。仔细分析一下,分发现其实有许多重复计算。比如s="ccaaa", t="ca"。计算第一个c之后,会dfs到后面3个a的情况。然后回溯到第二个c的时候,又会再dfs到后面3个a。于是可以用dp来做。

用nums[i][j]表示t[i...t.length-1]和s[j...s.length-1]有多少个Distinct Subsequences。我们最终求解就是nums[0][0]。

1. 如果t[i] = s[j],那么nums[i][j]应该等于t[i...t.length-1]和s[j+1...s.length-1]的数目,还要加上前一个字符累计的数目,也就是t[i+1...t.length-1]和s[j+1...s.length-1]的数目。比如t="ca", s="ccaaa"。nums[0][1]=3,t[0]=s[0],那么nums[0][0]应该就等于"ca"和“caaa”的数目(nums[0][1]),加上“a"和”caaa“之间的数目(nums[1[1]),所以nums[0][0]=nums[0][1]+nums[1][1]=3+3=6;

2. 如果t[i]!=s[j],那么nums[i][j]应该等于t[i...t.length-1]和s[j+1...s.length-1]的数目。比如t="ca", s="ccaaa", t[0]!=s[2],那么nums[0][2]应该等于"ca"和”aa"的数目,nums[0][2]=nums[0][3]=0。

3. 关于初始值:

nums[t.length][j...s.length]也就是t为空时,s[j...s.length]的数目,初始值应该为1,应该s[j...s.length]中有一个子串是空串。其他初始值都为0.

比如t="ca", s="ccaaa"。nums[1][3]=nums[1][4]+nums[2][4]=(nums[1][5]+nums[2][5])+nums[2][4]=(0+1)+1=2.

 1 class Solution {
 2 public:
 3     int numDistinct(string S, string T) {
 4         if (T.empty()) return 0;
 5         if (S.empty()) return 0;
 6         int n1 = S.length();
 7         int n2 = T.length();
 8         vector<vector<int> > nums(n2 + 1, vector<int>(n1 + 1, 0));
 9         for (int i = 0; i <= n1; ++i) {
10             nums[n2][i] = 1;
11         }
12         for (int i = n2 - 1; i >= 0; --i) {
13             for (int j = n1 - 1; j >= 0; --j) {
14                 if (T[i] == S[j]) {
15                     nums[i][j] = nums[i][j + 1] + nums[i + 1][j + 1];
16                 } else {
17                     nums[i][j] = nums[i][j + 1];
18                 }
19             }
20         }
21         
22         return nums[0][0];
23     }
24 };

 用一个滑动数组来优化一下,空间复杂度就是O(n),n是T的长度。

 1 class Solution {
 2 public:
 3     int numDistinct(string S, string T) {
 4         if (S.empty() || T.empty()) return 0;
 5         int n1 = S.length(), n2 = T.length();
 6         vector<vector<int> > dp(2, vector<int>(n2 + 1, 0));
 7         int cur = 0, next = 1;
 8         for (int i = n1 - 1; i >= 0; --i) {
 9             dp[cur][n2] = 1;
10             for (int j = n2 - 1; j >= 0; --j) {
11                 if (S[i] == T[j]) dp[next][j] = dp[cur][j + 1] + dp[cur][j];
12                 else dp[next][j] = dp[cur][j];
13             }
14             cur = !cur; next = !next;
15         }
16         return dp[cur][0];
17     }
18 };
原文地址:https://www.cnblogs.com/linyx/p/3720591.html