当前位置:主页 > c/c++教程 > C C++算法数组字符串匹配

C C++算法题解LeetCode1408数组中的字符串匹配

发布:2023-03-04 09:30:01 59


给网友们整理相关的编程文章,网友龚景曜根据主题投稿了本篇教程内容,涉及到C、C++算法数组字符串匹配、C、C++、数组字符串匹配、C C++算法数组字符串匹配相关内容,已被768网友关注,内容中涉及的知识点可以在下方直接下载获取。

C C++算法数组字符串匹配

题目描述

题目链接:1408. 数组中的字符串匹配

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

如果你可以删除 words[j] 最左侧和/或最右侧的若干字符得到 word[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"]
输出: []

整理题意

题目给定一个字符串数组 words,对于数组中的每个字符串来说,如果该字符串为数组中其他某个字符串的子串,那么就将该字符串加入答案字符串数组。可以按照任意顺序返回该答案数组。

解题思路分析

注意题目的数据提示:题目数据 保证 每个 words[i] 都是独一无二的。所以不存在两个相同的字符串,也避免了互为子字符串的情况。

根据题目数据范围来看,完全可以采用较为暴力的方法来进行解题,枚举每个字符串作为子串,检查是否为其他某个字符串的子串即可。

优化

在字符串匹配的时候可以采用 KMP 字符串匹配算法来进行优化时间复杂度。

具体实现

对于字符串匹配部分可以调用 string 中的 find() 函数进行匹配 t.find(p)(在字符串 t 中匹配字符串 p,也就是查找字符串 t 中是否包含字符串 p):

  • 此处需要用到 string 库中的 find() 函数与 string::npos 参数;

string::npos 参数是一个常数,用来表示不存在的位置。

  • stringfind() 返回值是子串的第一个字符在母串中的位置(下标记录),如果没有找到,那么会返回一个特别的标记 string::npos

可以对字符串数组 words 进行排序处理,这样就可以从最短的字符串开始匹配,且每次往后遍历匹配,因为前面的字符串一定短于当前字符串。

在使用 KMP 字符串匹配算法时需要注意:

  • KMP 字符串匹配算法的核心思想是 递归回溯思想,当匹配失败时根据 nxt 数组来进行回溯跳转;
  • nxt 数组表示模式串的子串的前缀和后缀相同的最长长度,这样就可以在匹配的过程中如果遇到不匹配的字符,模式串用 nxt 数组进行递归跳转到最长符合的位置进行继续匹配,从而不需要目标串进行重复的往返匹配。
  • 其中需要要注意的一个技巧是 nxt[0] = -1,在把 nxt 数组进行向右偏移时,第 0 位的值,我们将其设成了 -1,这只是为了编程的方便,并没有其他的意义。
  • 还需要注意 nxt 数组的优化,优化后在回溯跳转的时候会回溯跳转到首次与当前字符不一样字符的位置,避免了跳转到和当前字符一样的位置进行重复判断。
  • 在实现 getNext() 函数的时候需要注意 nxt 数组溢出问题,可以通过增加 nxt 数组大小,或减少 getNext() 函数中循环遍历的次数来防止越界出现的运行错误。
  • 需要注意在 getNext() 函数中 j 的初始化为 -1,但在 KMP() 函数中 j 的初始化为 0

复杂度分析

代码实现

暴力

class Solution {
public:
    vector stringMatching(vector& words) {
        // 新知识:string::npos
        vector ans;
        ans.clear();
        // 双重循环暴力寻找
        for(auto &word1 : words){
            int l1 = word1.length();
            for(auto &word2 : words){
                int l2 = word2.length();
                // 当 l2 大于 l1 时 并且可以在 w2 中找到 w1 时
                if(l1 < l2 && word2.find(word1) != string::npos){
                    ans.emplace_back(word1);
                    break;
                }
            }
        }
        return ans;
    }
};

暴力 + 优化

class Solution {
public:
    vector stringMatching(vector& words) {
        sort(words.begin(), words.end(), [](string &a, string &b){
            return a.length() < b.length();
        });
        // 新知识:string::npos
        vector ans;
        ans.clear();
        int n = words.size();
        // 双重循环暴力寻找
        for(int i = 0; i < n; i++){
            int l1 = words[i].length();
            for(int j = i + 1; j < n; j++){
                int l2 = words[j].length();
                // 当 l2 大于 l1 时 并且可以在 w2 中找到 w1 时
                if(l1 < l2 && words[j].find(words[i]) != string::npos){
                    ans.emplace_back(words[i]);
                    break;
                }
            }
        }
        return ans;
    }
};

KMP

class Solution {
    void getNext(string &p, vector &nxt){
        // 把PMT进行向右偏移时,第0位的值,我们将其设成了-1,
        // 这只是为了编程的方便,并没有其他的意义。
        nxt[0] = -1;
        int i = 0, j = -1;
        int len = p.length();
        // ★注意 nxt 数组越界
        while(i < len){
            // j = -1 或者 匹配成功
            if(j == -1 || p[i] == p[j]){
                // nxt[++i] = ++j; 未优化前
                i++;
                j++;
                if(p[i] == p[j]) nxt[i] = nxt[j];
                else nxt[i] = j;
            }
            // 匹配失败,回溯
            else{
                j = nxt[j];
            }
        }
    }
    bool kmp(string &t, string &p, vector &nxt){
        // ★注意这里的 j = 0 不是 j = -1
        int i = 0, j = 0;
        int lent = t.length();
        int lenp = p.length();
        while(i < lent && j < lenp){
            if(j == -1 || t[i] == p[j]){
                ++i;
                ++j;
            }
            else j = nxt[j];
        }
        if(j == lenp) return true;
        return false;
    }
public:
    vector stringMatching(vector& words) {
        sort(words.begin(), words.end(), [](string a, string b){
            return a.length() < b.length();
        });
        vector ans;
        ans.clear();
        vector nxt;
        int n = words.size();
        for(int i = 0; i < n; i++){
            int len_p = words[i].length();
            // ★注意 nxt 数组溢出
            // 可以这里 len_p + 1 也可以 getNext 中 -1
            nxt.resize(len_p + 1);
            getNext(words[i], nxt);
            for(int j = i + 1; j < n; j++){
                if(kmp(words[j], words[i], nxt)){
                    ans.emplace_back(words[i]);
                    break;
                }
            }
        }
        return ans;
    }
};

总结

  • 通过该题了解到了一个新的知识点:string::npos 参数用来表示不存在的位置。当 stringfind() 函数没有匹配成功时,那么就会返回这个参数 string::npos
  • 同时通过该题复习了 KMP 字符串匹配算法 的实现,在实现过程中需要注意 nxt 数组的大小,防止下标越界的运行错误;同时还需要注意在 getNext() 函数中 j 的初始化为 -1,但在 KMP() 函数中 j 的初始化为 0

测试结果:

以上就是C C++算法题解LeetCode1408数组中的字符串匹配的详细内容,更多关于C C++算法数组字符串匹配的资料请关注码农之家其它相关文章!


参考资料

相关文章

  • Python argparse命令参数与config配置参数示例深入详解

    发布:2023-03-14

    这篇文章主要介绍了Python argparse命令参数与config配置参数,argparse是Python内置的一个用于命令项选项与参数解析的模块,通过在程序中定义好我们需要的参数,然后在程序启动命令行传递我们想要改变的参数


  • 详解C++中类的六大默认成员函数

    发布:2023-03-04

    这篇文章主要介绍了C++类中的六大默认成员函数的原理雨使用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下


  • jquery如何操作select

    发布:2020-02-01

    这篇文章主要介绍了jquery下拉select控件操作方法分享(jquery操作select),需要的朋友可以参考下


  • SpringCloud实现简单的微服务架构方法

    发布:2019-06-18

    Spring Cloud是一系列框架的有序集合,本文就使用SpringCloud实现一套简单的微服务架构,具有一定的参考价值,感兴趣的小伙伴们可以参考一下


  • JavaScript中this关键字的使用方法

    发布:2020-03-12

    this是函数内部的对象并且被用于调用该函数,this在全局中的使用非常之灵活,下面就带大家来详解JavaScript中this关键字的用法


  • C语言#define定义宏的使用详解

    发布:2023-03-06

    #define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(define macro)。本文就来和大家聊聊宏的使用,需要的可以参考一下


  • 利用tkinter改变下拉列表(Combobox)的选项值

    发布:2023-03-13

    这篇文章主要介绍了利用tkinter改变下拉列表(Combobox)的选项值,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教


  • Python/MySQL实现Excel文件自动处理数据功能

    发布:2023-03-31

    在没有服务器存储数据,只有excel文件的情况下,如何利用SQL和python实现数据分析和数据自动处理的功能?本文就来和大家聊聊解决办法


网友讨论