Leetcode392.判断子序列

题目链接

点我(^_^)

题目大意

题干说得已经很清楚了。
Leetcode392.判断子序列_第1张图片

解题思路

利用指向字符串 s 的指针,遍历字符串 t, 每次判断当前字符是否和指针指向 s 的字符一致,如果一致,则指针右移一位,如果到尾部,则匹配成功。如果遍历完 t 指针还未到 s 尾部,则匹配失败。

代码(C++)

class Solution {
public:
    bool isSubsequence(string s, string t) {
        if(s=="" && t=="")
            return true;
        int l_s = 0;
        for(int i=0; i<t.size(); ++i)
        {
            if(s[l_s] == t[i])
                l_s++;
            if(l_s == s.size())
                return true;
        }
        return false;
    }
};

进阶思路

单论这一题没什么好说的,很简单,但是进阶版本还是很有意思的。如果现在有大量的 S,比如 k 个,需要你判断是否是 T 的子序列。那么之前的解法时间复杂度为 O(kt),这里 k 代表 S 的个数,t 代表字符串 T 的长度。如果 k>=10亿,那么时间复杂度会非常大。因此,我们可以思考是否可以通过预处理 T,产生一些中间结果,来辅助 S 的匹配,以此来降低时间复杂度。
之前我们匹配字符串时,是不满足字符相等条件,依次向后遍历 T,直到出现满足字符相等条件,当前字符算匹配上,如果我们不用依次向后遍历,而是根据当前字符直接找出下一个满足字符相等条件的位置在哪,就可以节约大量的时间。所以,我们可以预处理出一个 t*26 的矩阵 M,表示 T 的每个字符,对应 26 个字母的下一个位置在哪。
比如,对于字符串 T=“ahbgdc”,第一个字符对应的 26 字母数组如下。

M[0][a] = -1 //-1表示之后没有a字符
M[0][b] = 2 // 2表示下一个b在2这个位置
M[0][c] = 5 // 5表示下一个c在5这个位置
....

利用预处理的中间结果,完成匹配的时间复杂度为 O(s1+s2+…+sk),sk 表示第 k 个串的长度。
至于怎么预处理出矩阵 M,可以采用从后往前遍历字符串 T 的方式,维护一个字符最后出现位置的数组 pos,那么对于当前位置,就可以根据 pos 判断出 26 个字母下一次出现的位置,更新完 M 后,将该位置字母更新 pos 数组。

进阶代码(C++)

class Solution {
public:
    bool isSubsequence(string s, string t) {
        if(s=="" && t=="")
            return true;
        int M[t.size()+5][26];
        int pos[26];
        for(int i=0; i<26; ++i)
            pos[i] = -1;
        for(int i=t.size()-1; i>=0; i--) //预处理
        {
            for(int j=0; j<26; ++j)
                M[i+1][j] = pos[j];
            pos[t[i]-'a'] = i;
        }
        // 因为第一个字符可能不匹配,这里加入一个空字符以开始匹配
        for(int j=0; j<26; ++j)
            M[0][j] = pos[j];
        int l=0; //l表示当前在t的哪个位置
        for(int i=0; i<s.size(); ++i)
        {
            if(M[l][s[i]-'a'] == -1)
                return false;
            l = M[l][s[i]-'a']+1;
        }
        return true;
    }
};

你可能感兴趣的:(力扣刷题笔记,算法,leetcode,数据结构)