Day55
392.判断子序列
题目链接:392.判断子序列
与1143.最长公共子序列 几乎相同
class Solution {
public:
bool isSubsequence(string s, string t) {
vector<vector<int>> dp(s.size() + 1, vector<int>(t.size() + 1, 0));
for (int i = 1; i < s.size() + 1; ++i) {
for (int j = 1; j < t.size() + 1; ++j) {
dp[i][j] = (s[i - 1] == t[j - 1])
? dp[i - 1][j - 1] + 1
: dp[i][j - 1];
}
}
return dp.back().back() == s.size();
}
};
将dp
数组压缩至一维,有
class Solution {
public:
bool isSubsequence(string s, string t) {
vector<int> dp(t.size() + 1, 0);
for (int i = 1; i < s.size() + 1; ++i) {
int prev = 0;
for (int j = 1; j < t.size() + 1; ++j) {
int temp = dp[j]; // 保存当前 dp[j] 的值
dp[j] = (s[i - 1] == t[j - 1])
? prev + 1
: max(dp[j], dp[j - 1]);
prev = temp; // 更新 prev
}
}
return dp.back() == s.size();
}
};
对于每个位置 (i, j)
,其中 i
代表字符串 s
的索引,j
代表字符串 t
的索引,计算 dp[j]
的值。具体做法如下:
- 如果
s[i - 1]
等于t[j - 1]
,即当前字符匹配,则dp[j]
的值等于prev + 1
,其中prev
是上一个位置(i - 1, j - 1)
的值。 - 如果
s[i - 1]
不等于t[j - 1]
,即当前字符不匹配,则dp[j]
的值等于dp[j]
和dp[j - 1]
中的较大值。dp[j - 1]
是上一行对应位置的值,即(i, j - 1)
为了在计算新值之前保存 dp[j]
的旧值,使用变量 temp
。
115.不同的子序列
题目链接:115.不同的子序列
可以当做删除s
中其他元素,有多少种和t
相同的个数。
dp
数组 : 以i - 1
为结尾的s
中有以j - 1
为结尾的t
的个数为dp[i][j]
个
递推公式:
dp[i][j] = (s[i - 1] == t[j - 1])
? dp[i - 1][j - 1] + dp[i - 1][j]
: dp[i - 1][j];
dp[i - 1][j - 1] + dp[i - 1][j]
dp[i - 1][j - 1]
相当于s
变成i - 2
结尾,删除了第i - 1
个元素dp[i - 1][j]
这个情况就是题目中所描述的情况,比如s
是bagg
,t
是bag
。可以有s
中ba_g
和t
bag
匹配上,dp[i - 1][j - 1]
的状态,也可以是s
中bag_
和t
bag
匹配上,就是dp[i - 1][j]
的状态。
dp[i - 1][j]
删除s
的第i - 1
个元素,不考虑第i-1
个元素。
由于题目中的s
和t
的地位不同(t
是子集,s
是全集),因此有dp[i - 1][j]
状态出现,而没有dp[i][j - 1]
状态出现。
初始化:
二维数组初始化第一行和第一列。
dp[i][0] = 1
t
为空字符在s
中有1
种,dp[0][j] = 0
t
在s
空字符中有0
种
上述两个交集:dp[0][0] = 1
空字符t
在空字符s
中有1
种
class Solution {
public:
int numDistinct(string s, string t) {
vector<vector<unsigned/*int会溢出*/>> dp(s.size() + 1, vector<unsigned>(t.size() + 1, 0));
for (auto& tmp : dp) {
tmp[0] = 1;//初始化dp[i][0]
}
for (int i = 1; i < s.size() + 1; ++i) {
for (int j = 1; j < t.size() + 1; ++j) {
dp[i][j] = (s[i - 1] == t[j - 1])
? dp[i - 1][j - 1] + dp[i - 1][j]
: dp[i - 1][j];
}
}
return dp.back().back();
}
};
dp
数组压缩为一维数组
class Solution {
public:
int numDistinct(string s, string t) {
vector<unsigned> dp(t.size() + 1, 0);
dp[0] = 1;
for (int i = 1; i <= s.size(); i++) {
int prev = 1;
for (int j = 1; j <= t.size(); j++) {
int temp = dp[j];
if (s[i - 1] == t[j - 1]) {
dp[j] = prev + dp[j];
}
prev = temp;
}
}
return dp.back();
}
};
对于每个字符s[i - 1]
和t[j - 1]
,若它们相等,则可以选择将s[i - 1]
与t[j - 1]
匹配,此时,我们需要在s
的前i - 1
个字符和t
的前j - 1
个字符中找到不同子序列的个数,即dp[j - 1]
。同时,我们还可以选择不将s[i - 1]
与t[j - 1]
匹配,此时,我们需要在s
的前i - 1
个字符和t
的前j
个字符中找到不同子序列的个数,即dp[j]
。因此,当前字符的不同子序列的个数等于这两种选择的和。
在内层循环中,我们使用prev
变量来保存上一次迭代时的dp[j]
的值,以便在计算dp[j]
时使用。这样可以确保计算当前字符的不同子序列的个数时,使用的是上一次迭代时的值而不是当前迭代时的值。