LeetCode每日一题打卡(2) 1408. 数组中的字符串匹配

2022.8.6 每日一题

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"]
输出:[]

提示

1 <= words.length <= 100
1 <= words[i].length <= 30
words[i] 仅包含小写英文字母。
题目数据 保证 每个 words[i] 都是独一无二的。

解法1

由提示可知给定的字符串数组中字符串数量最多100个,字符串长度不超过30,直接模拟需要比较的次数最多为30*30*100*100即9e6次,时间复杂度O(n^{2}*L^{2}),数据不大,第一反应就是暴力求解绝对没问题。但是第一次提交WA了,原因是重复的字符串没有去除,暴力求解O(n^{2})比较每个字符串时如果一个较短的字符串被比较两次,也就是说如果一个字符串同时是另外两个字符串的子串,那结果只应被记录一次。

代码

class Solution {
public:
    vector<string> stringMatching(vector<string>& words) {
        vector<string>ans;
        int flag[110]={0};
        int len=words.size();
        for(int i=0;i<len;i++)
        {
            for(int j=0;j<len;j++)
            {
                if(j!=i&&solve(words[i],words[j])==1&&flag[j]==0)
                {
                    ans.push_back(words[j]);
                    flag[j]=1;
                }
            }
        }
        return ans;
    }
    int solve(string a,string b){
        int len1=a.size(),len2=b.size();
        if(len1<len2)
        return 0;
        int i=0,j=0;
        while(i<len1)
        {
            int k=i;
            for(j=0;j<len2;j++)
            {
                if(a[k]!=b[j])
                break;
                k++;
            }
            if(j==len2)
            return 1;
            i++;
        }
        return 0;
    }
};

代码思路

总的来说就是暴力模拟,solve函数用来判断字符串b是不是字符串a的子串,是返回1,不是返回0,其时间复杂度为O(L^{2})。flag数组用来记录结果是否已经被包含,也就是上面所说的去重。这种解法思路很容易,当然暴力解法从来都不是最优解。

解法2

参考了一下大佬的题解,看到最离谱的还有用AC自动机实现的线性复杂度的算法。。。就我这水平目前是看不懂的,也就不放上来了。这里介绍下利用C++的algorithm库自带的find函数写的解法,将所有给定的字符串利用逗号“,”分隔,拼接成一个长字符串,利用find函数查找每个字符串数组成员,如果一个成员在长字符串中被找到两次,那么就说明这个字符串一定是其他成员的子串,思路挺巧的也不难理解,代码也好写,复杂度主要取决于find函数,这个函数的底层实现我没有查到,运行结果表明其复杂度远不到O(n^{2}),显然比解法1更优。

代码

class Solution {
public:
    vector<string> stringMatching(vector<string>& words) {
        string all;
        vector<string>ans;
        int len=words.size();
        for(int i=0;i<len;i++)
        all=all+words[i]+",";
        for(int i=0;i<len;i++)
        {
            if(all.find(words[i])!=all.rfind(words[i]))
            ans.push_back(words[i]);
        }
        return ans;
    }
};

代码思路

代码也不难理解,而且相当好写,all存储拼接出的长字符串,find()查找字符串出现的第一个位置,rfind()查找字符串出现的最后一个位置,两个位置不同说明长字符串至少包含两个该子串。

总结

这题给的难度是easy,直接暴力就能过的确实简单,当然对于这样的简单题也要追求适当的优化,活用C++的库函数就很重要。

猜你喜欢

转载自blog.csdn.net/qq_43824745/article/details/126192097