Skip to content
本页目录

0392-判断子序列

https://leetcode.cn/problems/is-subsequence

给定字符串 s 和 t ,判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。

进阶: 如果有大量输入的 S,称作 S1, S2, ... , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码? 致谢: 特别感谢 @pbrother 添加此问题并且创建所有测试用例。

示例 1:

输入:s = "abc", t = "ahbgdc"
输出:true

示例 2:

输入:s = "axc", t = "ahbgdc"
输出:false

提示:

0 <= s.length <= 100
0 <= t.length <= 10^4
两个字符串都只由小写字符组成。

基本思路【ME】

判断 s 是否是 t 的子串,首先判断 s 的第sIndex = 0个字符在 t 中是否存在,如果存在则由 tIndex. 继续判断 s 剩下的字符串s[sIndex+1]到结尾 是否是 t[tIndex+1] 到结尾的子串,递归判断。
当 sIndex 先到达末尾,则判断结束, 返回 true,当 tIndex 先到达结尾说明有字符没有匹配到,返回 false

参考代码

csharp
public class Solution {
    private bool IsSub(string s, string t, int sIndex, int tIndex){
        if(sIndex >= s.Length){
            return true;
        }
        if(tIndex >= t.Length){
            return false;
        }
        bool found = false;
        int foundIndex = 0;
        //Console.WriteLine("Enter loop sIndex {0} tIndex {1}", sIndex, tIndex);
        for(int i=tIndex; i<t.Length; i++){
            if(s[sIndex] == t[i]){
                found = true;
                foundIndex = i;
                //Console.WriteLine("found {0} foundIndex {1}",found, foundIndex);
                break;
            }
        }
        found = found && IsSub(s,t,sIndex+1,foundIndex+1);
        return found;
    }

    public bool IsSubsequence(string s, string t) {
        return IsSub(s,t,0,0);
    }
}

思路2:双指针【对思路1进行简化】

csharp
public class Solution {
	public bool IsSubsequence(string s, string t) {
        int sIndex = 0;
        int tIndex = 0;
        while(sIndex < s.Length && tIndex < t.Length){
        	if(s[sIndex] == t[tIndex]){
        		sIndex++;
        	}
        	tIndex++;
        }
        //如果都s进行到结尾了,说明找到匹配字符串
        return sIndex == s.Length;
    }
}

思路3:动态规划

定义 dp[i,j] 表示 s 前 i 个字符,和 t 前 j 个字符 ,是否构成i是j的子序列。 注意包含关系的状态转移

csharp
public class Solution{
    public bool IsSubsequence(string s, string t){
        int m = s.Length;
        int n = t.Length;
        //动态规划 dp[i,j] 表示 s中前i个字符和t中前j个字符是否构成子序列关系
        bool[,] dp = new bool[m+1,n+1];
        //初始化,i为0都是包含于j的
        for(int j=0;j<=n;j++){
            dp[0,j] = true;
        }
        //状态转移
        for(int i=1; i<=m; i++){
            for(int j=1; j<=n; j++){
                if(s[i-1] == t[j-1]){
                    dp[i,j] = dp[i-1,j-1];
                }
                else{
                    //如果不相等,如果不包含j是子序列的话,那么本次也是子序列
                    dp[i,j] = dp[i,j-1];
                }
            }
        }
        return dp[m,n];
    }
}

复习双指针:20220515

csharp
public class Solution {
    public bool IsSubsequence(string s, string t) {
        if(s.Length == 0){
            return true;
        }
        int index=0; // source 串索引
        for(int i=0; i<t.Length; i++){
            if(s[index] == t[i]){
                index++;
            }
            if(index == s.Length){
                return true;
            }
        }
        return false;
    }
}

复习动规:20220515

注意初始化dp[0,j] 的都是 true,不只是dp[0,0]

csharp
public class Solution {
    public bool IsSubsequence(string s, string t) {
        if(s.Length == 0){
            return true;
        }
        int m = s.Length;
        int n = t.Length;
        bool[,] dp = new bool[m+1,n+1]; 
        for(int j=0; j<=n; j++){
            dp[0,j] = true; //都是空是符合子序列的
        }
        
        for(int i=1; i<=m; i++){
            for(int j=1; j<=n; j++){
                if(s[i-1] == t[j-1]){
                    dp[i,j] = dp[i-1,j-1]; 
                }
                else{
                    dp[i,j] = dp[i,j-1]; 
                }
            }
        }
        return dp[m,n];
    }
}

Released under the MIT License.