Cover image for 面试经典150题 P392 判断子序列

面试经典150题 P392 判断子序列


时间轴

时间轴

2025-10-15

init

双指针,动态规划

题目:

双指针

双指针分别指向 s 和 t,如果匹配上了就两个指针都向前移动,如果没有匹配上则指向 t 的指针向前移动,注意空字符串要单独处理。

123456789101112131415161718192021222324252627282930313233343536
#include <string>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;	}};#include <stdio.h>int main(){	Solution solution;	string s = "abc";	string t = "ahbgdc";	printf("%d\n", solution.isSubsequence(s, t));}

动态规划

考虑前面的双指针的做法,我们注意到我们有大量的时间用于在 t 中找到下一个匹配字符。这样我们可以预处理出对于 t 的每一个位置,从该位置开始往后每一个字符第一次出现的位置。我们可以使用动态规划的方法实现预处理:

f[i][j] f[i][j] 表示字符串 t 中从位置 i 开始往后字符 j 第一次出现的位置。

状态转移时:如果 t 中位置 i 的字符就是 j,那么 f[i][j]=if[i][j]=i,否则 j 出现在位置 i+1 开始往后,即 f[i][j]=f[i+1][j]f[i][j]=f[i+1][j],因此我们需要从后向前构建 dp

状态转移方程是:

f[i][j]={it[i]=jf[i+1][j]t[i]jf[i][j] = \begin{cases} i & t[i] = j \\ f[i+1][j] & t[i] \neq j \end{cases}

边界条件为:

f[m][j]=mj{0,1,,25}f[m][j] = m \quad \forall j \in \{0, 1, \dots, 25\}

其中:

  • ii 表示字符串 tt 中的位置(从 0 开始,0 ≤ i ≤ m)
  • jj 表示字符的编号(通常 ‘a’ 对应 0,‘b’ 对应 1,…,‘z’ 对应 25)
  • f[i][j]=mf[i][j] = m 表示从位置 ii 开始往后不存在字符 jj
1234567891011121314151617181920212223242526272829303132333435
#include <vector>#include <string>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;        }};
评论加载中…