[LeetCode] 392、判断子序列

题目描述

给定字符串 st ,判断 s 是否为 t 的子序列。

后续挑战:如果有大量输入的 S,称作S1, S2, … , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码?

解题思路

子序列不要求连续,仅仅要求不改变字符的相对顺序即可。

  • 直接法:直接判断子序列这个没什么好说的了,直接 O ( n ) O(n) 就可以得出结果,不需要动态规划,反而麻烦了。
    • 分别给两个字符串设置两个指针(index),在t中去匹配ss能完全匹配时返回true,一次遍历即可。
  • 动态规划法:纯粹是为了练习下“动态规划”才这么做的,时间/空间相率不高。
    • 状态:dp[i][j]s的从头开始到i的子字符串是否为t从头开始到j的子字符串的子序列。
    • 状态转移公式:
      • char[i] == char[j]时,dp[i][j] = dp[i-1][j-1]
      • char[i] != char[j]时,即判断当前0~i子字符串是否是0~j-1的子字符串的子序列,即dp[i][j] = dp[i][j-1]
    • 初始化:空字符串一定是t的子字符串的子序列,所以dp[0][j] = true,其余位置均初始化为false。(由状态转移方程可知,其实这里需要同时初始化第0行和第0列,但是可以先指定二维数组全为false,然后只初始化第0行就可以了)
  • 后续挑战:重要的是要明白思路,肯定是用空间换时间。
    • 创建一个哈希表,存储t中26个小写字母及每个字母出现的下标,下标按照升序排序。(也可用数组实现简单的哈希表:vector<vector<int>>dp(26)
    • 例如:dp[0]存储了字符a出现在t的所有位置的下标,逐个字符判断s的字符顺序是否在t内,直接返回结果。
    • 因为索引是递增的,所以我们可以使用二分查找s的单个字符。(见题解代码即可)

参考代码

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

后续挑战(题解代码)

bool isSubsequence(string s, string t) {        
    vector<vector<int> > dp(26);
    int tag=-1;
    for(int i=0;i<t.size();i++)
        dp[t[i]-'a'].push_back(i);
    for(int i=0;i<s.size();i++){
        int now=s[i]-'a';
        int left=0,right=dp[now].size()-1;
        while(left<right){
            int mid=(left+right)/2;
            if(dp[now][mid]>tag)
                right=mid;
            else
                left=mid+1;
        }
        if(right<left || dp[now][left]<tag)return false;
        tag=dp[now][left];
    
    }
    
    return true;
}
发布了390 篇原创文章 · 获赞 576 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/ft_sunshine/article/details/103844286
今日推荐