给定一个整数数组,求最大连续子序列和。(至少包含一个元素)
示例:
dp[i]:包括下标i(以nums[i]为结尾)的最大连续子序列和为dp[i]。
- class Solution {
- public:
- int maxSubArray(vector<int>& nums) {
- if (nums.size() == 0) return 0;
- vector<int> dp(nums.size());
- dp[0] = nums[0];
- int result = dp[0];
- for (int i = 1; i < nums.size(); i++) {
- dp[i] = max(dp[i - 1] + nums[i], nums[i]); // 状态转移公式
- if (dp[i] > result) result = dp[i]; // result 保存dp[i]的最大值
- }
- return result;
- }
- };
用递推公式 dp[i] = max(dp[i - 1] + nums[i], nums[i])推导可以看出,若上一步的dp值加上当前遍历的nums值 大于 当前遍历的nums值,则取dp[i - 1] + nums[i],否则取nums[i]。
这样可以保证连续的值一直是最大值,不符和就从当前的nums值重新开始。
给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。
dp[i][j] 表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度为dp[i][j]。
- class Solution {
- public:
- bool isSubsequence(string s, string t) {
- vector
int>> dp(s.size() + 1, vector<int>(t.size() + 1, 0)); - for (int i = 1; i <= s.size(); i++) {
- for (int j = 1; j <= t.size(); j++) {
- if (s[i - 1] == t[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1;
- else dp[i][j] = dp[i][j - 1];
- }
- }
- if (dp[s.size()][t.size()] == s.size()) return true;
- return false;
- }
- };
给定一个字符串 s 和一个字符串 t ,计算在 s 的子序列中 t 出现的个数。
dp[i][j]:以i-1为结尾的s子序列中出现以j-1为结尾的t的个数为dp[i][j]。
- class Solution {
- public:
- int numDistinct(string s, string t) {
- vector
uint64_t>> dp(s.size() + 1, vector<uint64_t>(t.size() + 1)); - for (int i = 0; i < s.size(); i++) dp[i][0] = 1;
- for (int j = 1; j < t.size(); j++) dp[0][j] = 0;
- for (int i = 1; i <= s.size(); i++) {
- for (int j = 1; j <= t.size(); j++) {
- if (s[i - 1] == t[j - 1]) {
- dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
- } else {
- dp[i][j] = dp[i - 1][j];
- }
- }
- }
- return dp[s.size()][t.size()];
- }
- };
给定两个单词 word1 和 word2,找到使得 word1 和 word2 相同所需的最小步数,每步可以删除任意一个字符串中的一个字符。
dp[i][j]:以i-1为结尾的字符串word1,和以j-1位结尾的字符串word2,想要达到相等,所需要删除元素的最少次数。
- class Solution {
- public:
- int minDistance(string word1, string word2) {
- vector
int>> dp(word1.size() + 1, vector<int>(word2.size() + 1)); - for (int i = 0; i <= word1.size(); i++) dp[i][0] = i;
- for (int j = 0; j <= word2.size(); j++) dp[0][j] = j;
- for (int i = 1; i <= word1.size(); i++) {
- for (int j = 1; j <= word2.size(); j++) {
- if (word1[i - 1] == word2[j - 1]) {
- dp[i][j] = dp[i - 1][j - 1];
- } else {
- dp[i][j] = min({dp[i - 1][j - 1] + 2, dp[i - 1][j] + 1, dp[i][j - 1] + 1})
- }
- }
- }
- return dp[word1.size()][word2.size()];
- }
- };
看见了最左上角的右边和下边从0开始赋值的初始化1...n
字符匹配dp[i][j] = dp[i - 1][j - 1];字符不匹配 dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1);
最后结果依照dp数组定义,返回最右下角值
当word1[i - 1] 与 word2[j - 1]相同的时候,dp[i][j] = dp[i - 1][j - 1];
当word1[i - 1] 与 word2[j - 1]不相同的时候,有三种情况:
情况一:删word1[i - 1],最少操作次数为dp[i - 1][j] + 1
情况二:删word2[j - 1],最少操作次数为dp[i][j - 1] + 1
情况三:同时删word1[i - 1]和word2[j - 1],操作的最少次数为dp[i - 1][j - 1] + 2
取最小值递推公式:dp[i][j] = min({dp[i - 1][j - 1] + 2, dp[i - 1][j] + 1, dp[i][j - 1] + 1});
从递推公式 dp[i][j] = min(dp[i - 1][j - 1] + 2, min(dp[i - 1][j], dp[i][j - 1]) + 1); 和dp[i][j] = dp[i - 1][j - 1]可以看出dp[i][j]都是根据左上方、正上方、正左方推出来的。(同时遍历顺序也要求左到右,上到下,包装存在这些值)
所以dp[i][0] 和 dp[0][j]一定要初始化的。
一边单词为0的字符串,另一边要怎么删才相等呢,当然是有多少删多少,一个为i,一个为j
- vector
int>> dp(word1.size() + 1, vector<int>(word2.size() + 1)); - for (int i = 0; i <= word1.size(); i++) dp[i][0] = i;
- for (int j = 0; j <= word2.size(); j++) dp[0][j] = j;
给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
插入一个字符
删除一个字符
替换一个字符
示例 2:
输入:word1 = "intention", word2 = "execution"
输出:5
解释: intention -> inention (删除 't') inention -> enention (将 'i' 替换为 'e') enention -> exention (将 'n' 替换为 'x') exention -> exection (将 'n' 替换为 'c') exection -> execution (插入 'u')
dp[i][j] 表示以下标i-1为结尾的字符串word1,和以下标j-1为结尾的字符串word2,最近编辑距离为dp[i][j]。
dp[i][j]由4种情况推出,
- if (word1[i - 1] == word2[j - 1])
- 不操作
- if (word1[i - 1] != word2[j - 1])
- 增
- 删
- 换
word1[i - 1] == word2[j - 1]时
不操作:dp[i][j] = dp[i - 1][j - 1];这里就是匹配成功不用操作的意思(继承之前的操作次数)
word1[i - 1] != word2[j - 1]时
操作数+1,忽略当前值,继续遍历寻找匹配值
这里的删除相当于增加,word2添加一个元素,相当于word1删除一个元素,
例如 word1 = "ad" ,word2 = "a"
,word1
删除元素'd'
和 word2
添加一个元素'd'的操作数都是1,由于求的也是操作数,所以,增加word1一次相当于删除word2一次
所以
增加公式:dp[i][j] = dp[i][j - 1] + 1;
换改后,word1[i - 1] 和word2[j - 1]从不相等变成了相等,所以用 dp[i][j] = dp[i - 1][j - 1];
综合后递归公式代码如下:
- if (word1[i - 1] == word2[j - 1]) {
- dp[i][j] = dp[i - 1][j - 1];
- }
- else {
- dp[i][j] = min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1;
- }
dp[i][j]的定义:
dp[i][j] 表示以下标i-1为结尾的字符串word1,和以下标j-1为结尾的字符串word2,最近编辑距离为dp[i][j]。
dp[i][0] :以下标i-1为结尾的字符串word1,和空字符串word2,最近编辑距离为dp[i][0]。
那么dp[i][0]就应该是i,对word1里的元素全部做删除操作,即:dp[i][0] = i;
同理dp[0][j] = j;
- for (int i = 0; i <= word1.size(); i++) dp[i][0] = i;
- for (int j = 0; j <= word2.size(); j++) dp[0][j] = j;
由图可看出,递推公式依赖关系。即从左到右从上到下去遍历。
- class Solution {
- public:
- int minDistance(string word1, string word2) {
- vector
int>> dp(word1.size() + 1, vector<int>(word2.size() + 1, 0)); - for (int i = 0; i <= word1.size(); i++) dp[i][0] = i;
- for (int j = 0; j <= word2.size(); j++) dp[0][j] = j;
- for (int i = 1; i <= word1.size(); i++) {
- for (int j = 1; j <= word2.size(); j++) {
- if (word1[i - 1] == word2[j - 1]) {
- dp[i][j] = dp[i - 1][j - 1];
- }
- else {
- dp[i][j] = min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1;
- }
- }
- }
- return dp[word1.size()][word2.size()];
- }
- };
115和583被吞了。