【五十二】【算法分析与设计】28. 找出字符串中第一个匹配项的下标,1408. 数组中的字符串匹配,1455. 检查单词是否为句中其他单词的前缀,KMP算法应用,string内置函数寻找子串

 

目录

28. 找出字符串中第一个匹配项的下标

string内置函数find

暴力枚举

KMP算法

主逻辑

next逻辑

1408. 数组中的字符串匹配

string内置函数find

KMP算法

1455. 检查单词是否为句中其他单词的前缀

结尾


28. 找出字符串中第一个匹配项的下标

给你两个字符串 haystackneedle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1

示例 1:

输入:haystack = "sadbutsad", needle = "sad" 输出:0 解释:"sad" 在下标 0 和 6 处匹配。 第一个匹配项的下标是 0 ,所以返回 0 。

示例 2:

输入:haystack = "leetcode", needle = "leeto" 输出:-1 解释:"leeto" 没有在 "leetcode" 中出现,所以返回 -1 。

提示:

  • 1 <= haystack.length, needle.length <= 10(4)

  • haystackneedle 仅由小写英文字符组成

string内置函数find

1.

string类内置方法find,str.find(match)作用是在str内部寻找与match相匹配的子串,默认从0开始寻找。

str.find(match,5)作用是在str内部寻找与match相匹配的子串,从下标5开始寻找。

 
class Solution {
public:
    int strStr(string haystack, string needle) {
        return haystack.find(needle);
    }
};

暴力枚举

1.

如果不用内置函数,暴力遍历,时间复杂度O(O*M)。

2. if (needle.size() > haystack.size()) return -1;

如果模式串的长度大于匹配串,不可能找到,直接返回-1。

3. for (int i = 0; i < haystack.size(); i++) {

遍历所有开始匹配的位置,从这个位置开始匹配。

4. int j = i; int k = 0; while (j < haystack.size() && k < needle.size() && haystack[j] == needle[k]) { j++, k++; }

如果退出循环,k指针遍历完所有的元素,此时表示找到了,返回j-k。 if (k == needle.size()) return j - k; }

否则返回-1.表示没有找到。 return -1; } };

 
class Solution {
public:
    int strStr(string haystack, string needle) {
        if (needle.size() > haystack.size())
            return -1;
        for (int i = 0; i < haystack.size(); i++) {
            int j = i;
            int k = 0;
            while (j < haystack.size() && k < needle.size() &&
                   haystack[j] == needle[k]) {
                j++, k++;
            }
            if (k == needle.size())
                return j - k;
        }
        return -1;
    }
};

KMP算法

1.

KMP算法,时间复杂度O(N)。

主逻辑

2.

主函数内部逻辑,定义x,y双指针模拟匹配串和模式串的当前匹配下标。

x指针不回退,y指针回退。

x指针是匹配串的当前匹配下标。

y指针是模式串当前匹配下标。

3.

如果当前x,y位置匹配,x++,y++。

4.

如果当前x,y位置不匹配,选择y回退,y回退到next[y]位置。

即y=next[y]。

5.

当需要执行y=next[y]这条语句的时候,需要保证next[y]!=-1,也就是需要保证y!=0。

6.

如果y==0,此时x直接++,此时的x和y正好是下一个位置开始匹配的位置。

next逻辑

7.

人为规定,next[0]=-1,next[1]=0。

8.

一开始while里面cn为next[i-1],这是默认的但是不能显示赋值,如果显示赋值那么cn不会发生改变,会一直等于next[i-1],所以我们需要控制cn每次计算新的i需要等于next[i-1]。

9.

如果match[cn]==match[i-1],next[i]=cn+1。i++,cn=cn+1。

10.

如果match[cn]!=match[i-1],cn=next[cn]。

11.

需要执行cn=next[cn]这条语句,需要保证next[cn]!=-1,也就是cn!=0。

12.

如果cn==0还不匹配,next[i]=0。

 
class Solution {
public:
    int strStr(string haystack, string needle) {
        if (needle.size() > haystack.size())
            return -1;
        vector<int> next = getNext(needle);
        int x = 0, y = 0;
        while (x < haystack.size() && y < needle.size()) {
            if (haystack[x] == needle[y]) {
                x++, y++;
            } else if (y != 0) {
                y = next[y];
            } else {
                x++;
            }
        }
        if (y == needle.size())
            return x - y;
        else
            return -1;
    }

    vector<int> getNext(string match) {
        if (match.size() == 1)
            return {-1};
        vector<int> next(match.size());
        next[0] = -1, next[1] = 0;
        int i = 2;
        int cn = 0;
        while (i < next.size()) {
            if (match[cn] == match[i - 1]) {
                next[i++] = ++cn;
            } else if (cn != 0) {
                cn = next[cn];
            } else {
                next[i++] = 0;
            }
        }
        return next;
    }
};

1408. 数组中的字符串匹配

给你一个字符串数组 words ,数组中的每个字符串都可以看作是一个单词。请你按 任意 顺序返回 words 中是其他单词的子字符串的所有单词。

如果你可以删除 words[j] 最左侧和/或最右侧的若干字符得到 words[i] ,那么字符串 words[i] 就是 words[j] 的一个子字符串。

示例 1:

输入:words = ["mass","as","hero","superhero"] 输出:["as","hero"] 解释:"as" 是 "mass" 的子字符串,"hero" 是 "superhero" 的子字符串。 ["hero","as"] 也是有效的答案。

示例 2:

输入:words = ["leetcode","et","code"] 输出:["et","code"] 解释:"et" 和 "code" 都是 "leetcode" 的子字符串。

示例 3:

输入:words = ["blue","green","bu"] 输出:[]

提示:

  • 1 <= words.length <= 100

  • 1 <= words[i].length <= 30

  • words[i] 仅包含小写英文字母。

  • 题目数据 保证 每个 words[i] 都是独一无二的。

string内置函数find

 
class Solution {
public:
    vector<string> stringMatching(vector<string>& words) {
        vector<string> ret;
        for (int i = 0; i < words.size(); i++) {
            for (int j = 0; j < words.size(); j++) {
                if (i != j && words[j].find(words[i]) != string::npos) {
                    ret.push_back(words[i]);
                    break;
                }
            }
        }
        return ret;
    }
};

KMP算法

 
class Solution {
public:
    vector<string> stringMatching(vector<string>& words) {
        vector<string> ret;
        for (int i = 0; i < words.size(); i++) {
            for (int j = 0; j < words.size(); j++) {
                if (i != j && strStr(words[j], words[i])) {
                    ret.push_back(words[i]);
                    break;
                }
            }
        }
        return ret;
    }
    bool strStr(string haystack, string needle) {
        if (needle.size() > haystack.size())
            return false;
        vector<int> next = getNext(needle);
        int x = 0, y = 0;
        while (x < haystack.size() && y < needle.size()) {
            if (haystack[x] == needle[y]) {
                x++, y++;
            } else if (y != 0) {
                y = next[y];
            } else {
                x++;
            }
        }
        if (y == needle.size())
            return true;
        else
            return false;
    }

    vector<int> getNext(string match) {
        if (match.size() == 1)
            return {-1};
        vector<int> next(match.size());
        next[0] = -1, next[1] = 0;
        int i = 2;
        int cn = 0;
        while (i < next.size()) {
            if (match[cn] == match[i - 1]) {
                next[i++] = ++cn;
            } else if (cn != 0) {
                cn = next[cn];
            } else {
                next[i++] = 0;
            }
        }
        return next;
    }
};

1455. 检查单词是否为句中其他单词的前缀

给你一个字符串 sentence 作为句子并指定检索词为 searchWord ,其中句子由若干用 单个空格 分隔的单词组成。请你检查检索词 searchWord 是否为句子 sentence 中任意单词的前缀。

如果 searchWord 是某一个单词的前缀,则返回句子 sentence 中该单词所对应的下标(下标从 1 开始)。如果 searchWord 是多个单词的前缀,则返回匹配的第一个单词的下标(最小下标)。如果 searchWord 不是任何单词的前缀,则返回 -1

字符串 s前缀s 的任何前导连续子字符串。

示例 1:

输入:sentence = "i love eating burger", searchWord = "burg" 输出:4 解释:"burg" 是 "burger" 的前缀,而 "burger" 是句子中第 4 个单词。

示例 2:

输入:sentence = "this problem is an easy problem", searchWord = "pro" 输出:2 解释:"pro" 是 "problem" 的前缀,而 "problem" 是句子中第 2 个也是第 6 个单词,但是应该返回最小下标 2 。

示例 3:

输入:sentence = "i am tired", searchWord = "you" 输出:-1 解释:"you" 不是句子中任何单词的前缀。

提示:

  • 1 <= sentence.length <= 100

  • 1 <= searchWord.length <= 10

  • sentence 由小写英文字母和空格组成。

  • searchWord 由小写英文字母组成。

1.

利用双指针分割所有的单词,装到words数组中。

2.

定义cur指向当前单词的首字母,pos查找当前单词后面出现的空格。

3.

如果找到了空格,说明这个单词不是最后一个出现的单词。

4.

单词的长度是pos-cur,获取sentence的子串,利用内置函数substr(cur,length),从cur位置开始往后长度为length的子串。

5.

获取此时单词后,维护cur=pos+1,表示下一个单词的首字母位置。

6.

pos=pos+1,表示下一个空格开始寻找的位置。

7.

如果从pos位置开始查找找不到空格,说明此时是最后一个单词。

8.

直接获取cur位置到结尾的子串即可。

 
class Solution {
public:
    int isPrefixOfWord(string sentence, string searchWord) {
        vector<string> words;
        int pos = 0;
        int cur = 0;
        while (1) {
            pos = sentence.find(" ", pos);
            if (pos != string::npos) {
                int length = pos - cur;
                words.push_back(sentence.substr(cur, length));
                cur = pos + 1;
                pos++;
            } else {
                words.push_back(sentence.substr(cur));
                break;
            }
        }
        // for(auto x:words){
        //     cout<<x<<" ";
        // }

        for (int i = 0; i < words.size(); i++) {
            if (words[i].substr(0, searchWord.size()) == searchWord) {
                return i + 1;
            }
        }
        return -1;
    }
};

结尾

最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。

同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。

谢谢您的支持,期待与您在下一篇文章中再次相遇!

  • 9
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

妖精七七_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值