【精】LintCode领扣算法问题答案:1024. 满足要求的子串个数

这篇文章探讨了解决字符串S中子序列计数问题的算法,重点讲解了如何利用nextPosCache进行缓存优化,提升匹配效率。通过示例和代码实现,深入剖析了如何判断一个单词是否为S的子序列,并指出其在实际问题中的应用价值。
摘要由CSDN通过智能技术生成

1024. 满足要求的子串个数

描述

给定一个字符串S 和一个单词字典 words,问, words中一共有多少个单词words[i]是字符串S的子序列?

注意, 子序列不同于子串, 子序列不要求连续.

  • 所有words 内的单词和 S只包含小写字母.
  • S的长度在 [1, 50000]范围内.
  • words的长度在 [1, 5000]范围内.
  • words[i]的长度在[1, 50]范围内.

样例 1:

输入: 
	S = "abcde", words = ["a", "bb", "acd", "ace"]
输出: 
	3
解释: 
	words内有三个单词是S的子串: "a", "acd", "ace".

样例 2:

输入: 
	S = "dsahjpjauf", words = ["ahjpjau","ja","ahbwzgqnuk","tnmlanowax"]
输出: 
	2

原题传送门



题解

题解

public class Solution {
    /**
     * @param S:     a string
     * @param words: a dictionary of words
     * @return: the number of words[i] that is a subsequence of S
     */
    public int numMatchingSubseq(String S, String[] words) {
        // Write your code here

        int ret = 0;

        int[][] nextPosCache = new int[S.length()][26];
        for (String word : words) {
            if (this.isSubSeq(S, word, nextPosCache)) {
                ++ret;
            }
        }

        return ret;
    }

    /**
     * @param S
     * @param word
     * @param nextPosCache
     * @return
     */
    private boolean isSubSeq(String S, String word, int[][] nextPosCache) {
        int    sLen = nextPosCache.length;
        int    wLen = word.length();

        // 比S还长,肯定不是子序列
        if (wLen > sLen) {
            return false;
        }

        char[] wcs  = word.toCharArray();
        int    sI, wI;

        for (wI = 0, sI = 0; wI < wLen && sI < sLen; ++wI, ++sI) {
            char wc   = wcs[wI];
            int  wcI  = wc - 'a';

            int  tmpI = nextPosCache[sI][wcI];

            if (tmpI == 0) {
                // 缓存未命中
                tmpI = S.indexOf(wc, sI);
                int maxI;
                if (tmpI < 0) {
                    maxI = wLen - 1;
                } else {
                    maxI = tmpI;
                }
                for (int i = sI; i <= maxI; ++i) {
                    if (nextPosCache[i][wcI] != 0) {
                        break;
                    }
                    nextPosCache[i][wcI] = tmpI;
                }
            }

            if (tmpI < 0) {
                return false;
            }

            sI = tmpI;
        }

        return wI == wLen;
    }
}

分析

代码并不复杂,也不难理解:

  • numMatchingSubseq方法是入口方法,没什么特别,就是遍历所有待匹配的字符串,匹配成功就将结果自增1。
  • isSubSeq方法用来判断参数word是否是参数S的子序列,这是能否通过的关键。而此方法的关键就是S.indexOf(wc, sI)这一句,这是自带的api,就是返回字符串S中从位置sI开始第一个出现wc字符的位置,不存在则返回-1。
  • nextPosCache作为延迟加载的缓存,起到加速的作用,可以想象的到,越往后,缓存命中率越高。虽然没有它也完全可以通过,但是有和没有的运行速度有明显的差距。nextPosCache[i][c - ‘a’]的意思就是从位置i开始第一次出现字符c的位置。另外,第一个字符相当于没有缓存,因为判断缓存未命中是用的0,但是结合indexOf的实现,我觉得这里利大于弊,如果缓存未命中的值换成别的,就需要初始化缓存。

最后说两句

非常感谢你阅读本文章,如果你觉得本文对你有所帮助,请留下你的足迹,点个赞,留个言,多谢~

作者水平有限,如果文章内容有不准确的地方,请指正。

希望小伙伴们都能每天进步一点点。

声明

本文由二当家的白帽子博客原创,转载请注明来源,谢谢~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二当家的白帽子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值