[算法]LeetCode每日一题--392. 判断子序列(Java)

DailyChallenge

392. 判断子序列

Easy20200727

Description

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

你可以认为 s 和 t 中仅包含英文小写字母。字符串 t 可能会很长(长度 ~= 500,000),而 s 是个短字符串(长度 <=100)。

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

示例 1:
s = "abc", t = "ahbgdc"

返回 true.

示例 2:
s = "axc", t = "ahbgdc"

返回 false.

后续挑战 :

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

链接https://leetcode-cn.com/problems/is-subsequence

Solution

  1. 双指针,遍历两个字符串
class Solution {
    public boolean isSubsequence(String s, String t) {
        int m = s.length();
        int n = t.length();
        // 双指针遍历,暴力法,但是没有用到s很短,t很长的这一个特点
        int i = 0, j = 0;
        while(i < m && j < n){
            if(s.charAt(i) == t.charAt(j)){
                i++;
                j++;
            }else{
                j++;
            }
        }
        return i == m;
    }
}
  1. 后续挑战

动态规划,注意t很长,s很短这个特点。将t字符串预处理。

闫式DP分析法

  • 状态表示:dp[i][j]表示字符串t中从i往后,包括i,字符j第一次出现的位置;dp[n + 1][26]
  • 状态计算:找第一次出现的位置,倒序遍历。
    • if(t.charAt(i) - 'a' == j) dp[i][j] = i;:如果t的第i个字符就是j,那么第一次出现的位置就是i;
    • else dp[i][j] = dp[i + 1][j];:如果t的第i个字符不是j,那么就dp[i][j] = dp[i + 1][j]
  • 初始化:dp[n][0 ~ 25] = -1 表示找不到。

通过预处理字符串t,如果有大量的s字符串,能够保证O(n)的时间复杂度。

class Solution {
    public boolean isSubsequence(String s, String t) {
        // 动态规划预处理t数组
        int m = s.length();
        int n = t.length();

        // 状态表示:dp[i][j]表示字符串t中从i往后,包括i,字符j第一次出现的位置
        int[][] dp = new int[n + 1][26];
        // 初始化 dp[n][0 ~ 25]
        for(int j = 0; j < 26; j++){
            // 赋值为-1表示i之后找不到字符j
            dp[n][j] = -1;
        }

        // 状态计算, 倒序动态规划
        // 1. if t[i] == j; dp[i][j] = i;
        // 2. if t[i] != j; dp[i][j] = dp[i + 1][j];

        for(int i = n - 1; i >= 0; i--){
            for(int j = 0; j < 26; j++){
                if(t.charAt(i) - 'a' == j) dp[i][j] = i;
                else dp[i][j] = dp[i + 1][j];
            }
        }
        // 开始找字符串s
        int index = 0;
        for(int i = 0; i < m; i++){
            int c = s.charAt(i) - 'a';
            // 如果找不到,就直接返回false
            if(dp[index][c] == -1) return false;
            // 如果存在,那么c就在t的dp[index][c]位置,所以找下一个字符,应该从dp[index][c] + 1开始找
            index = dp[index][c] + 1;
        }
        return true;
    }
}


我的公众号:GitKid

暂时每日分享LeetCode,我在不断学习的过程中,公众号也在不断充实,欢迎大家扫码关注。

TODO:动态规划专题

微信公众号

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值