时间轴
时间轴
2025-10-15
init
双指针,动态规划
题目:
双指针
双指针分别指向 s 和 t,如果匹配上了就两个指针都向前移动,如果没有匹配上则指向 t 的指针向前移动,注意空字符串要单独处理。
123456789101112131415161718192021222324252627282930313233343536 | using std::string;class Solution { public: bool isSubsequence(string s, string t) { // 判断s是否为t的子字符串 int i = 0, j = 0; int s_len = s.size(); int t_len = t.size(); if (s_len == 0) { return true; } while (i < s_len && j < t_len) { if (s[i] == t[j]) { i++; } j++; } if (i == s_len && s[i - 1] == t[j - 1]) { return true; } return false; }};int main(){ Solution solution; string s = "abc"; string t = "ahbgdc"; printf("%d\n", solution.isSubsequence(s, t));} |
动态规划
考虑前面的双指针的做法,我们注意到我们有大量的时间用于在 t 中找到下一个匹配字符。这样我们可以预处理出对于 t 的每一个位置,从该位置开始往后每一个字符第一次出现的位置。我们可以使用动态规划的方法实现预处理:
令 表示字符串 t 中从位置 i 开始往后字符 j 第一次出现的位置。
状态转移时:如果 t 中位置 i 的字符就是 j,那么 ,否则 j 出现在位置 i+1 开始往后,即 ,因此我们需要从后向前构建 dp
状态转移方程是:
边界条件为:
其中:
- 表示字符串 中的位置(从 0 开始,0 ≤ i ≤ m)
- 表示字符的编号(通常 ‘a’ 对应 0,‘b’ 对应 1,…,‘z’ 对应 25)
- 表示从位置 开始往后不存在字符
1234567891011121314151617181920212223242526272829303132333435 | using std::vector;using std::string;class Solution { public: bool isSubsequence(string s, string t) { int n = s.size(), m = t.size(); // m+1是为了处理边界情况 vector<vector<int> > f(m + 1, vector<int>(26, 0)); for (int i = 0; i < 26; i++) { f[m][i] = m; } for (int i = m - 1; i >= 0; i--) { for (int j = 0; j < 26; j++) { if (t[i] == j + 'a') f[i][j] = i; else f[i][j] = f[i + 1][j]; } } int add = 0; for (int i = 0; i < n; i++) { if (f[add][s[i] - 'a'] == m) { return false; } add = f[add][s[i] - 'a'] + 1; } return true; }}; |
