匹配子序列的单词数

给定字符串 S 和单词字典 words, 求 words[i] 中是 S 的子序列的单词个数。

示例:
输入:
S = “abcde”
words = [“a”, “bb”, “acd”, “ace”]
输出: 3
解释: 有三个是 S 的子序列的单词: “a”, “acd”, “ace”。

注意:

所有在words和 S 里的单词都只由小写字母组成。
S 的长度在 [1, 50000]。
words 的长度在 [1, 5000]。
words[i]的长度在[1, 50]。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-matching-subsequences
因为 S 很长,所以寻找一种只需遍历一次 S 的方法,避免暴力解法的多次遍历。

解题思路:将所有单词根据首字母不同放入不同的桶中。例如当 words = [‘dog’, ‘cat’, ‘cop’],根据首字母不同可以分为 ‘c’ : (‘cat’, ‘cop’), ‘d’ : (‘dog’,)。换句话说,每个桶中的单词就是该单词正在等待匹配的下一个字母。在遍历 S 的同时,将匹配到单词根据下一个需要匹配的字母移动到不同的桶中。

例如,有字符串 S = ‘dcaog’:

初始化 heads = 'c' : ('cat', 'cop'), 'd' : ('dog',);
遍历 S[0] = 'd' 后,heads = 'c' : ('cat', 'cop'), 'o' : ('og',);
遍历 S[1] = 'c' 后,heads = 'a' : ('at',), 'o' : ('og', 'op');
遍历 S[2] = 'a' 后,heads = 'o' : ('og', 'op'), 't': ('t',) ;
遍历 S[3] = 'o' 后,heads = 'g' : ('g',), 'p': ('p',), 't': ('t',);
遍历 S[0] = 'g' 后,heads = 'p': ('p',), 't': ('t',)。

算法

使用长度为 26 的数组 heads 做桶,每个字母对应一个桶。访问 S 中的每个字母时,将该字母对应桶中的所有单词,根据下一个等待匹配字母放入到不同的桶中。如果已经匹配到单词的最后一个字母,那么子序列单词数加 1。

算法实现

struct Node{ //一个结构体就是一个word,这个word最多有5000个单词,每个最长50位
    char word[5000][51];
    int wordNum;
};

int numMatchingSubseq(char * S, char ** words, int wordsSize){
    struct Node barrels[26]; //设置26个桶,极端情况是所有的单词开头字母
    						 //都是一样的,这个桶依旧能装下
    int resultNum = 0;
    int strLen = strlen(S);
    int index = 0;
    char removeChar = 0;
    char secondChar = 0;
    for (int i = 0; i < 26; i++) {     //初始化26个桶
        for (int j = 0; j < 5000; ++j) {
            memset(barrels[i].word[j], 0, 51);
        }
        barrels[i].wordNum = 0;    //桶内单词数用来判断该单词放在桶内位置,
            						   //也就是word中的第几行
    }
    if (wordsSize <= 5000){
        for (int i = 0; i < wordsSize; i++) {  //将words存入到26个桶中
            int barrelIdx = words[i][0] - 'a';//判断属于哪个桶
            strcpy(barrels[barrelIdx].word[barrels[barrelIdx].wordNum], words[i]);//将该单词放到第几个桶(barrels[barrelIdx),该桶内第几个位置(word[barrels[barrelIdx].wordNum)
            barrels[barrelIdx].wordNum ++;     
        }
    }
    for (int j = 0; j < strLen; j++) {  //遍历S,消首字母,做桶操作
        int doubleChar[26] = {0};
        char temp[51] = {0};
        removeChar = S[j];  
        index = (int)(removeChar - 'a');
        if (index < 26){
            for (int i = 0; i < barrels[index].wordNum; i++) {
                if (strlen(barrels[index].word[i]) > 1){
                    if (barrels[index].word[i][1] == barrels[index].word[i][0]){  //首字母与第二字母相同
                        memset(temp, 0, 51);
                        strcpy(temp, barrels[index].word[i] + 1);//将首字母与第二字母相同的单词复制到temp
                        memset(barrels[index].word[doubleChar[index]], 0, 51);
                        strcpy(barrels[index].word[doubleChar[index]], temp);  //消首字母后复制到原始桶
                        doubleChar[index] ++;  //原始桶操作后单词个数记录
                    } else {  
                        secondChar = barrels[index].word[i][1] - 'a'; //决定放到哪个新桶
                        if (secondChar < 26){
                            strcpy(barrels[secondChar].word[barrels[secondChar].wordNum], barrels[index].word[i] + 1);  //消首字母后复制到新桶
                            barrels[secondChar].wordNum ++;  //单词数加1
                            memset(barrels[index].word[i], 0, 51); //复制前word[i]所在位置清空
                        }
                    }
                } else if (strlen(barrels[index].word[i]) == 1){  //最后一个字符
                    resultNum++;    //全部字符消除,子序列个数加1
                    memset(barrels[index].word[i], 0, 51);
                }
            }
            barrels[index].wordNum = doubleChar[index];  //遍历一个字符,操作一个桶,更新该桶wordNum
        }
    }
    return resultNum;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

乔二梦

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

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

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

打赏作者

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

抵扣说明:

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

余额充值