2022.8.6 每日一题
题目描述
给你一个字符串数组 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(),数据不大,第一反应就是暴力求解绝对没问题。但是第一次提交WA了,原因是重复的字符串没有去除,暴力求解O()比较每个字符串时如果一个较短的字符串被比较两次,也就是说如果一个字符串同时是另外两个字符串的子串,那结果只应被记录一次。
代码
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()。flag数组用来记录结果是否已经被包含,也就是上面所说的去重。这种解法思路很容易,当然暴力解法从来都不是最优解。
解法2
参考了一下大佬的题解,看到最离谱的还有用AC自动机实现的线性复杂度的算法。。。就我这水平目前是看不懂的,也就不放上来了。这里介绍下利用C++的algorithm库自带的find函数写的解法,将所有给定的字符串利用逗号“,”分隔,拼接成一个长字符串,利用find函数查找每个字符串数组成员,如果一个成员在长字符串中被找到两次,那么就说明这个字符串一定是其他成员的子串,思路挺巧的也不难理解,代码也好写,复杂度主要取决于find函数,这个函数的底层实现我没有查到,运行结果表明其复杂度远不到O(),显然比解法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++的库函数就很重要。