3

不同的子序列 II_安东尼漫长的技术岁月的技术博客_51CTO博客

 1 year ago
source link: https://blog.51cto.com/u_13961087/5755003
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

不同的子序列 II

精选 原创

掘金安东尼 2022-10-14 09:01:02 ©著作权

文章标签 子序列 动态规划 字符串 文章分类 JavaScript 前端开发 阅读数242

不同的子序列 II_动态规划

难度:困难

给定一个字符串 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 仅由小写英文字母组成

子序列的定义:从原序列中任意选择一些项,保持相对序列不变,得到的就是原序列的子序列

方程状态定义,dp[i]就为到索引为i的文字为止,能生成的子序列的个数

例如:初始状态dp[0] = dp[-1] * 2 + 1; // 非法的值赋为0,所以dp[0] 为1

状态方程推断

如果当前的文字没有出现过,那么当前位置能新生成子序列的个数就为,前一位的个数 + 自己,总数就为 前一位的个数 + 前一位的个数 + 1

dp[I] = dp[i-1] * 2 - 1;

如果当前的文字出现过,自己就不能加进去了,新生成的就为 前一位的个数 + 前一位的个数 - 重复的个数 此时重复的个数是多少呢,是这个文字前一次的位置的【除了自己以外的新生成】,假设这个文字当前的位置是i,上一次位置是j,那么重复的个数为dp[j - 1]

/**
* @param {string} S
* @return {number}
*/
var distinctSubseqII = function (S) {
const dp = [];
const count = {};
const MOD = 1000000007;
let length = S.length;
for (let i = 0; i < length; i++) {
const preDp = dp[i - 1] || 0;
if (typeof count[S[i]] === 'undefined') {
dp[i] = preDp * 2 + 1;
} else {
const prePositionDp = dp[count[S[i]] - 1] || 0;
dp[i] = preDp * 2 - prePositionDp;
if (dp[i] < 0) {
dp[i] += MOD;
}
}
dp[i] %= MOD;
count[S[i]] = i;
}
return dp[S.length - 1];
};

动态规划是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。 动态规划常常适用于有重叠子问题和最优子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。 动态规划背后的基本思想非常简单。


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK