跳转至

115. 不同的子序列

难度:困难

题目

给定一个字符串 s 和一个字符串 t ,计算在 s 的子序列中 t 出现的个数。

字符串的一个 子序列 是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,"ACE" 是 "ABCDE" 的一个子序列,而 "AEC" 不是)

题目数据保证答案符合 32 位带符号整数范围。

示例 1:

输入:s = "rabbbit", t = "rabbit"
输出:3
解释:
如下图所示, 有 3 种可以从 s 中得到 "rabbit" 的方案。
(上箭头符号 ^ 表示选取的字母)
rabbbit
^^^^ ^^
rabbbit
^^ ^^^^
rabbbit
^^^ ^^^

示例 2:

输入:s = "babgbag", t = "bag"
输出:5
解释:
如下图所示, 有 5 种可以从 s 中得到 "bag" 的方案。 
(上箭头符号 ^ 表示选取的字母)
babgbag
^^ ^
babgbag
^^    ^
babgbag
^    ^^
babgbag
  ^  ^^
babgbag
    ^^^

提示:

  • 0 <= s.length, t.length <= 1000
  • st 由英文字母组成

Reference

题解

解题思路:设\(f(x, y)\)为字符串\(x\)中的子序列中字符串\(y\)出现的次数。并且使用\(x + 1\)表示字符串\(x\)从第二个字符开始的子串。

则:

  • \(x, y\)的第一个字符不同时,有\(f(x, y) = f(x + 1, y)\)
  • \(x, y\)的第一个字符匹配时,有\(f(x, y) = f(x + 1, y + 1) + f(x + 1, y)\)

特殊地,当\(y\)为空字符串时,说明字符串匹配结束,对应一个匹配成功的子串,因此\(f(x, \varnothing) = 1\)。当\(x\)为空字符串且\(y\)不为空字符串时,说明字符串匹配失败,\(f(\varnothing, y) = \left\{\begin{aligned}&0 &y\not = \varnothing \\ & 1 &y=\varnothing\end{aligned}\right .\)

由此,可以初步得出递归代码:

int numDistinct(char * s, char * t){
    if (!*t)
        return 1;
    if (!*s)
        return 0;
    int ret = 0;
    if (*s == *t)
        ret += numDistinct(s + 1, t + 1);
    ret += numDistinct(s + 1, t);
    return ret;
}

如上代码会造成超时,原因是递归时出现了分支导致时间复杂度为\(2^n\)。使用数组存储历史结果可以避免递归产生分支,优化时间复杂度:

int cached(char *s, char *t, int x, int y, int **buffer) {
    int ret = 0;
    if (!*t)
        ret = 1;
    else if (!*s)
        ret = 0;
    else
    {
        if (buffer[x][y] >= 0)
            return buffer[x][y];
        if (*s == *t)
            ret += cached(s + 1, t + 1, x + 1, y + 1, buffer);
        ret += cached(s + 1, t, x + 1, y, buffer);
        buffer[x][y] = ret;
    }
    return ret;
}
int numDistinct(char * s, char * t){
    int x = strlen(s), y = strlen(t);
    int *_buffer = (int *)malloc(sizeof(int) * x * y);
    int **buffer = (int **)malloc(sizeof(int *) * x);
    for (int i = 0; i < x; i++)
        buffer[i] = _buffer + i * y;
    memset(_buffer, 0xff, sizeof(int) * x * y);
    return cached(s, t, 0, 0, buffer);
}

评论