亲宝软件园·资讯

展开

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

Junkman丶 人气:0

题目描述

题目链接: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::npos 参数是一个常数,用来表示不存在的位置。

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

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

复杂度分析

代码实现

暴力

class Solution {
public:
    vector<string> stringMatching(vector<string>& words) {
        // 新知识:string::npos
        vector<string> 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<string> stringMatching(vector<string>& words) {
        sort(words.begin(), words.end(), [](string &a, string &b){
            return a.length() < b.length();
        });
        // 新知识:string::npos
        vector<string> 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<int> &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<int> &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<string> stringMatching(vector<string>& words) {
        sort(words.begin(), words.end(), [](string a, string b){
            return a.length() < b.length();
        });
        vector<string> ans;
        ans.clear();
        vector<int> 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;
    }
};

总结

测试结果:

加载全部内容

相关教程
猜你喜欢
用户评论