412,判断子序列

想了解更多数据结构以及算法题,可以关注微信公众号“数据结构和算法”,每天一题为你精彩解答。也可以扫描下面的二维码关注
在这里插入图片描述


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


示例 1:

s = “abc”, t = “ahbgdc”

返回 true.


示例 2:

s = “axc”, t = “ahbgdc”

返回 false.


双指针求解

这题让求的是s是否是t的子序列,我们可以使用两个指针,一个指向s的某个字符,一个指向t的某个字符,其中指向t的指针每次都会往右移一位,指向s的指针每次和指向t的指针所对应的字符相同时才会往右移,否则就不移动,当指向s的指针指向s的末尾的时候,返回true。这里以示例1为例来画个图看一下
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

原理很简单,我们来直接看下代码

public boolean isSubsequence(String s, String t) {
    if (s.length() == 0)
        return true;
    int indexS = 0, indexT = 0;
    while (indexT < t.length()) {
        if (t.charAt(indexT) == s.charAt(indexS)) {
            //指向s的指针只有在两个字符串相同时才会往右移
            indexS++;
            if (indexS == s.length())
                return true;
        }
        //指向t的指针每次都会往右移一位
        indexT++;
    }
    return false;
}

动态规划

我们用dp[i][j]表示字符串t的前j个字符包含s的前i个字符

所以递归公式是


1,s.charAt(i - 1) == t.charAt(j - 1)
dp[i][j] = dp[i - 1][j - 1]


2,s.charAt(i - 1) != t.charAt(j - 1)
dp[i][j] = dp[i][j - 1];


那么边界条件是什么呢,当s为空的时候,我们默认t是包含s的,所以当s为空的时候,返回true。有了递推公式和边界条件,代码就很容易写了,来看下

public boolean isSubsequence(String s, String t) {
    if (s.length() == 0)
        return true;
    boolean[][] dp = new boolean[s.length() + 1][t.length() + 1];
    //边界条件
    for (int i = 0; i < t.length(); i++) {
        dp[0][i] = true;
    }
    for (int i = 1; i <= s.length(); i++) {
        for (int j = 1; j <= t.length(); j++) {
            //递推公式
            if (s.charAt(i - 1) == t.charAt(j - 1)) {
                dp[i][j] = dp[i - 1][j - 1];
            } else {
                dp[i][j] = dp[i][j - 1];
            }
        }
    }
    return dp[s.length()][t.length()];
}

逐个查找

如果熟悉java语言的都知道,在java中String类有这样一个方法

public int indexOf(int ch, int fromIndex)

他表示的是在字符串中是否存在一个字符ch,并且是从字符串的下标fromIndex开始查找的。我们要做的是在t字符串中查找s中的每一个字符,如果没查到,直接返回false。如果查到,就从t的下一个位置继续开始查

public boolean isSubsequence(String s, String t) {
    int index = -1;
    for (char c : s.toCharArray()) {
        //index表示上一次查找的位置(第一次查找的时候为-1),
        // 所以这里要从t的下标(index+1)开始查找
        index = t.indexOf(c, index + 1);
        //没找到,返回false
        if (index == -1)
            return false;
    }
    return true;
}

参照最长公共子序列

看到这道题我们还可以参照之前写的370,最长公共子串和子序列,我们只要求出s和t的最长公共子序列的长度即可,如果长度等于s的长度,说明s就是t的子序列

public boolean isSubsequence(String s, String t) {
    int[] dp = new int[t.length() + 1];
    int last = 0;
    for (int i = 1; i <= s.length(); i++) {
        for (int j = 1; j <= t.length(); j++) {
            int temp = dp[j];
            if (s.charAt(i - 1) == t.charAt(j - 1))
                dp[j] = last + 1;
            else
                dp[j] = Math.max(dp[j], dp[j - 1]);
            last = temp;
        }
    }
    return dp[t.length()] == s.length();
}

总结

这题比较简单,但解法比较多,最容易想到的估计就是双指针了。

在这里插入图片描述

posted @ 2020-09-21 22:23  数据结构和算法  阅读(161)  评论(0编辑  收藏  举报