C C++算法題解LeetCode1408數(shù)組中的字符串匹配
題目描述
題目鏈接:1408. 數(shù)組中的字符串匹配
給你一個字符串數(shù)組 words ,數(shù)組中的每個字符串都可以看作是一個單詞。請你按 任意 順序返回 words 中是其他單詞的子字符串的所有單詞。
如果你可以刪除 words[j] 最左側(cè)和/或最右側(cè)的若干字符得到 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"]
輸出: []
整理題意
題目給定一個字符串數(shù)組 words,對于數(shù)組中的每個字符串來說,如果該字符串為數(shù)組中其他某個字符串的子串,那么就將該字符串加入答案字符串數(shù)組??梢园凑杖我忭樞蚍祷卦摯鸢笖?shù)組。
解題思路分析
注意題目的數(shù)據(jù)提示:題目數(shù)據(jù) 保證 每個 words[i] 都是獨一無二的。所以不存在兩個相同的字符串,也避免了互為子字符串的情況。
根據(jù)題目數(shù)據(jù)范圍來看,完全可以采用較為暴力的方法來進行解題,枚舉每個字符串作為子串,檢查是否為其他某個字符串的子串即可。
優(yōu)化
在字符串匹配的時候可以采用 KMP 字符串匹配算法來進行優(yōu)化時間復雜度。
具體實現(xiàn)
對于字符串匹配部分可以調(diào)用 string 中的 find() 函數(shù)進行匹配 t.find(p)(在字符串 t 中匹配字符串 p,也就是查找字符串 t 中是否包含字符串 p):
- 此處需要用到
string庫中的find()函數(shù)與string::npos參數(shù);
string::npos 參數(shù)是一個常數(shù),用來表示不存在的位置。
string中find()返回值是子串的第一個字符在母串中的位置(下標記錄),如果沒有找到,那么會返回一個特別的標記string::npos。
可以對字符串數(shù)組 words 進行排序處理,這樣就可以從最短的字符串開始匹配,且每次往后遍歷匹配,因為前面的字符串一定短于當前字符串。
在使用 KMP 字符串匹配算法時需要注意:
KMP字符串匹配算法的核心思想是 遞歸回溯思想,當匹配失敗時根據(jù)nxt數(shù)組來進行回溯跳轉(zhuǎn);nxt數(shù)組表示模式串的子串的前綴和后綴相同的最長長度,這樣就可以在匹配的過程中如果遇到不匹配的字符,模式串用nxt數(shù)組進行遞歸跳轉(zhuǎn)到最長符合的位置進行繼續(xù)匹配,從而不需要目標串進行重復的往返匹配。- 其中需要要注意的一個技巧是
nxt[0] = -1,在把nxt數(shù)組進行向右偏移時,第0位的值,我們將其設(shè)成了-1,這只是為了編程的方便,并沒有其他的意義。 - 還需要注意
nxt數(shù)組的優(yōu)化,優(yōu)化后在回溯跳轉(zhuǎn)的時候會回溯跳轉(zhuǎn)到首次與當前字符不一樣字符的位置,避免了跳轉(zhuǎn)到和當前字符一樣的位置進行重復判斷。 - 在實現(xiàn)
getNext()函數(shù)的時候需要注意nxt數(shù)組溢出問題,可以通過增加nxt數(shù)組大小,或減少getNext()函數(shù)中循環(huán)遍歷的次數(shù)來防止越界出現(xiàn)的運行錯誤。 - 需要注意在
getNext()函數(shù)中j的初始化為-1,但在KMP()函數(shù)中j的初始化為0。
復雜度分析

代碼實現(xiàn)
暴力
class Solution {
public:
vector<string> stringMatching(vector<string>& words) {
// 新知識:string::npos
vector<string> ans;
ans.clear();
// 雙重循環(huán)暴力尋找
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;
}
};
暴力 + 優(yōu)化
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();
// 雙重循環(huán)暴力尋找
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位的值,我們將其設(shè)成了-1,
// 這只是為了編程的方便,并沒有其他的意義。
nxt[0] = -1;
int i = 0, j = -1;
int len = p.length();
// ★注意 nxt 數(shù)組越界
while(i < len){
// j = -1 或者 匹配成功
if(j == -1 || p[i] == p[j]){
// nxt[++i] = ++j; 未優(yōu)化前
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 數(shù)組溢出
// 可以這里 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;
}
};
總結(jié)
- 通過該題了解到了一個新的知識點:
string::npos參數(shù)用來表示不存在的位置。當string中find()函數(shù)沒有匹配成功時,那么就會返回這個參數(shù)string::npos。 - 同時通過該題復習了 KMP 字符串匹配算法 的實現(xiàn),在實現(xiàn)過程中需要注意
nxt數(shù)組的大小,防止下標越界的運行錯誤;同時還需要注意在getNext()函數(shù)中j的初始化為-1,但在KMP()函數(shù)中j的初始化為0。
測試結(jié)果:



以上就是C C++算法題解LeetCode1408數(shù)組中的字符串匹配的詳細內(nèi)容,更多關(guān)于C C++算法數(shù)組字符串匹配的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C++ Qt開發(fā)之使用QHostInfo查詢主機地址
Qt 是一個跨平臺C++圖形界面開發(fā)庫,利用Qt可以快速開發(fā)跨平臺窗體應(yīng)用程序,本文將重點介紹如何運用QHostInfo組件實現(xiàn)對主機地址查詢功能,希望對大家有所幫助2024-03-03
C++程序中main(int argc, char *argv[])函數(shù)的參數(shù)意義
這篇文章主要介紹了C++程序中main(int argc, char *argv[])函數(shù)的參數(shù)意義,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2018-09-09

