动归

188 阅读1分钟

题目:

给定一个字符串 S,计算 S 的不同非空子序列的个数。 因为结果可能很大,所以返回答案模 10^9 + 7. 

 示例 1: 

输入:"abc" 
输出:7 解释:7 个不同的子序列分别是 "a", "b", "c", "ab", "ac", "bc", 以及 "abc"。

示例 2: 

输入:"aba" 
输出:6 解释:6 个不同的子序列分别是 "a", "b", "ab", "ba", "aa" 以及 "aba"。 

示例 3: 

输入:"aaa" 
输出:3 解释:3 个不同的子序列分别是 "a", "aa" 以及 "aaa"。 

解题

分析 但所有字母都不重复时 长度为i 的子序列(包括‘’空子序列)数 dp[i]  =  dp[i-1]*2

dp[1] = 2 
dp[2] = 4  
dp[3] = 8 

得到状态转移方程就可以,进行解题了,处理边界和异常情况就好了。

class Solution {
    public int distinctSubseqII(String S) {
        int MOD = 1_000_000_007;
        int N = S.length();
        int[] dp = new int[N+1];
        dp[0] = 1;

        int[] last = new int[26];//简单的hash表 记录是否重复出现
        Arrays.fill(last, -1);

        for (int i = 0; i < N; ++i) {
            int x = S.charAt(i) - 'a';
            dp[i+1] = dp[i] * 2 % MOD;
            if (last[x] >= 0) // -1 未出现 >0 表示已经在last[x]位置上出现过
                dp[i+1] -= dp[last[x]]; // 消除重复出
            dp[i+1] %= MOD;
            last[x] = i; // 记录上次出现的位置 
        }

        dp[N]--; // 去除空
        if (dp[N] < 0) dp[N] += MOD;
        return dp[N];
    }
}