给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。
进阶:
如果有大量输入的 S,称作 S1, S2, ... , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码?
示例 1:
输入:s = "abc", t = "ahbgdc"
输出:true
示例2:
输入:s = "axc", t = "ahbgdc"
输出:false
题目问s是否是t的序列,是返回true不是返回false,s可以不连续的出现在t中,最直接的方法就是:用i标记s遍历的位置,用j标记t遍历的位置,一旦t中的第j个字符与s串中第i个字符相同,记录下当前j的位置,作为查找s中第i+1个字符的起点,然后i后移一位(在匹配过程中无论是否匹配成功t串都会向后移动一位,s串只有匹配成功才会后移一位),如此,直至遍历完t串。如果s串比t串先遍历完的,那么说明s串为t串的子序列,返回true;如果因为遍历完t串而跳出遍历t串的内循环,也就是说从起点找到最后了都没有找到,s串的第i个字符,那么就返回false。两冲循环解决效率也是非常高的。
//C语言代码:
bool isSubsequence(char * s, char * t){
int step = 0,j;//step记录s串每一个字符进行匹配时遍历t串的起点;
for(int i = 0; s[i] != '\0'; i++)//遍历s串;
{
for(j = step; t[j] != '\0'; j++)//遍历t串;
{
if(t[j] == s[i])//成功匹配;
{
step = j+1;//记录位置作为s串下一个字符的遍历起点;
break;//跳出循环;
}
}
if(step != j+1)//如果不是因为成功匹配而跳出内循环,s不是t的子序列,返回false;
return false;
}
return true;//s优先t遍历结束,s是t的子序列返回true;
}
还是和往常一样,找到操作和状态,这道题不是一个实际问题,我们把它看成实际问题,如果让你现实生活中去完成这件事,你的操作是什么就是拿着s串的一个字符去和t串一个一个匹配,那么操作一个一个字符的匹配,状态又是什么呢?我们要完成匹配就是要看在找完一遍t串的时候s串完成匹配的字符个数和s串的长度是否相等,那么状态就是完成s串匹配的字符数量。我们可以建立一个二维数组dp[i][j]来记录在s串遍历到i,t串遍历到j时已经完成匹配的字符数(遍历到i和j时,实际匹配的是,s[i-1]和t[j-1],这个已经很关键,后面会一直用到)。
为了实现记录已经完成的匹配字符数,需要记录s的每一位i对应t的每一位j已经完成匹配的字符数,所以需要s中的每一个字符找到遍历到t的每一个字符时最多可以匹配的字符数。
当s串的第i位和t串的第j位,检测是否需要更新完成匹配的字符数。
如果需要,也就是说s[i-1] == t[i-1]此时的dp[i][j]就等于当s串遍历到i-1,t遍历到j-1时已经完成匹配(不包含s[i-1],t[j-1])的字符数+1。状态转移方程为:
dp[i][j] = dp[i-1][j-1]+1;
如果不需要,此时dp[i][j]就等于当s串遍历到第i位,t串遍历到第j-1位时已经完成匹配的字符数,也就是说这一次匹配s[i-1]和t[i-1]与上一次s[i-1]与t[j-2]的匹配说没有差别,状态转移方程:
dp[i][j] = dp[i][j-1]
注意:上面的数组的下标出现了i-1和j-1,数组的下标要大于0,所以遍历要从就j=1和i=1开始。
最后dp[i-1][j-1] 时候为s串的长度,如果是那么返回true,不是则返回false。
//C语言代码;
bool isSubsequence(char * s, char * t){
int dp[105][10005] = {0},i,j = 1;
for(i = 1; s[i-1] != '\0'; i++)//遍历s串;
{
for(j = 1; t[j-1] != '\0'; j++)//遍历t串;
{
if(t[j-1] == s[i-1])
{
dp[i][j] = dp[i-1][j-1]+1; //状态转移,找到在s第i位,t第j位已经完成的字符串匹配个数;
}
else
{
dp[i][j] = dp[i][j-1];//状态转移,与s第i位,t第j-1位已经完成的字符串匹配个数相同
}
}
}
if(dp[i-1][j-1] != i-1)//dp的右下角下标位[i-1][j-1],s字符长是i-1;
return false;
return true;
}
不得不说这段代码性能很差.......
ps:其实最好理解的方法还是画图!