zoukankan      html  css  js  c++  java
  • 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 };
  • 相关阅读:
    在Dictionary中使用枚举
    WCF中的可信赖会话
    C#中的结构与类
    当弱引用对象成为集合元素时
    如何打开软件从业之门?
    放心,它命硬着呢
    懒人的商品查询移动应用
    555的传说
    放松、自信和没受过欺负的脸
    才知道系列之GroupOn
  • 原文地址:https://www.cnblogs.com/linyx/p/3720591.html
Copyright © 2011-2022 走看看