题目描述
给定一个字符串 s,计算 s 的 不同非空子序列 的个数。因为结果可能很大,所以返回答案需要对 10^9 + 7 取余 。
字符串的 子序列 是经由原字符串删除一些(也可能不删除)字符但不改变剩余字符相对位置的一个新字符串。
例如,"ace" 是 "abcde" 的一个子序列,但 "aec" 不是。
数据样例&给定要求
示例 1:
输入:s = "abc"
输出:7
解释:7 个不同的子序列分别是 "a", "b", "c", "ab", "ac", "bc", 以及 "abc"。
示例 2:
输入:s = "aba"
输出:6
解释:6 个不同的子序列分别是 "a", "b", "ab", "ba", "aa" 以及 "aba"。
示例 3:
输入:s = "aaa"
输出:3
解释:3 个不同的子序列分别是 "a", "aa" 以及 "aaa"。
提示:
1 <= s.length <= 2000
s 仅由小写英文字母组成
题目思路
- 这是一道动态规划类型的题目
- 子序列问题我们要从以每一个位置作为结尾来进行考虑
- 子序列问题每一个位置我们做出俩个决策,选或者不选
- 最后子序列的结果就是以每一个字符结尾的所有子序列结果的累加和
- 共有26个小写字母,记录以每一个小写字母结尾形成子序列的个数,但是我们可能会出现重复的字母,所以我们通过数组来记录每个字母上一次出现的下标位置,然后求得以当前字母结尾的子序列个数,将所有的结果进行累加求得,最后取模
题目代码
方法一:
class Solution {
final int mod=1000000007;
public int distinctSubseqII(String s) {
char c[]=s.toCharArray();
long count[]=new long[26];
for(int i=0;i<c.length;i++){
int a=c[i]-'a';
for(int j=0;j<26;j++){
if(j!=a){
count[a]+=count[j];
}
}
count[a]=(count[a]+1)%mod;
}
long ans=0;
for(int i=0;i<26;i++){
ans+=count[i];
}
return (int)(ans%mod);
}
}
方法二:
class Solution {
final int mod=1000000007;
public int distinctSubseqII(String s) {
int n=s.length();
int[] res=new int[n];
int[] arr=new int[26];
Arrays.fill(res,1);
Arrays.fill(arr,-1);
for(int i=0;i<n;i++){
int index=s.charAt(i)-'a';
for(int j=0;j<26;j++){
if(arr[j]>=0){
res[i]=(res[i]+res[arr[j]])%mod;
}
}
arr[index]=i;
}
int sum=0;
for(int i=0;i<26;i++){
if(arr[i]>=0){
sum=(sum+res[arr[i]])%mod;
}
}
return sum%mod;
}
}