【每日演算法/刷穿 LeetCode】28. 實現 strStr()(簡單)
技術標籤:LeetCode 題解演算法與資料結構刷穿 LeetCode演算法javaleetcodepython資料結構
點選 這裡 可以檢視更多演算法面試相關內容~
題目描述
實現 strStr() 函式。
給定一個 haystack 字串和一個 needle 字串,在 haystack 字串中找出 needle 字串出現的第一個位置 (從0開始)。如果不存在,則返回 -1。
示例 1:
輸入: haystack = "hello", needle = "ll"
輸出: 2
示例 2:
輸入: haystack = "aaaaa", needle = "bba" 輸出: -1
說明:
當 needle
是空字串時,我們應當返回什麼值呢?這是一個在面試中很好的問題。
對於本題而言,當 needle
是空字串時我們應當返回 0 。這與C語言的 strstr()
以及 Java的 indexOf()
定義相符。
樸素解法
直觀的解法的是:列舉原串 ss
中的每個字元作為起點,構造一個和匹配串 pp
一樣長度的子串 sub
,將 sub
和 pp
做對比:
class Solution {
public int strStr(String ss, String pp) {
int n = ss.length(), m = pp.length();
for (int i = 0; i < n - m + 1; i++) {
String sub = ss.substring(i, i + m);
if (sub.equals(pp)) return i;
}
return -1;
}
}
-
時間複雜度:
n
為原串的長度,m
為匹配串的長度。其中列舉的複雜度為 O ( n − m ) O(n - m) O(n−m),構造和比較字串的複雜度為 O ( n ) O(n) O(n)。整體複雜度為 O ( ( n − m ) ∗ n ) O((n - m) * n) -
空間複雜度: O ( 1 ) O(1) O(1)
KMP 解法
KMP 演算法是一個快速查詢匹配串的演算法,時間複雜度為 O ( n ) O(n) O(n)。
建議和三葉在「5. 最長迴文子串」中提供的 Manacher 演算法一樣,進行背過。
KMP 演算法的應用範圍要比 Manacher 演算法要廣,Manacher 演算法只能應用於「迴文串」問題,較為侷限,而「子串匹配」問題還是十分常見的。
背過這樣的演算法的意義在於:相當於大腦裡有了一個時間複雜度為 O ( n ) O(n) O(n) 的 api 可以使用,這個 api 傳入一個原串和匹配串,返回匹配串在原串的位置。
一些相關的註釋我已經寫到程式碼裡:
class Solution {
// KMP 演算法
// ss: 原串 pp: 匹配串
public int strStr(String ss, String pp) {
if (pp.isEmpty()) return 0;
// 分別讀取原串和匹配串的長度
int n = ss.length(), m = pp.length();
// 原串和匹配串前面都加空格,使其下標從 1 開始
ss = " " + ss;
pp = " " + pp;
char[] s = ss.toCharArray();
char[] p = pp.toCharArray();
// 構建 next 陣列,陣列長度為匹配串的長度(next 陣列是和匹配串相關的)
int[] next = new int[m + 1];
// 構造過程 i = 2,j = 0 開始,i 小於等於匹配串長度 【構造 i 從 2 開始】
for (int i = 2, j = 0; i <= m; i++) {
// 匹配不成功的話,j = next(j)
while (j > 0 && p[i] != p[j + 1]) j = next[j];
// 匹配成功的話,j++
if (p[i] == p[j + 1]) j++;
next[i] = j;
}
// 匹配過程,i = 1,j = 0 開始,i 小於等於原串長度 【匹配 i 從 1 開始】
for (int i = 1, j = 0; i <= n; i++) {
// 匹配不成功 j = next(j)
while (j > 0 && s[i] != p[j + 1]) j = next[j];
// 匹配成功 j++
if (s[i] == p[j + 1]) j++;
// 如果匹配成功了,直接返回
if (j == m) return i - m;
}
return -1;
}
}
-
時間複雜度: O ( n ) O(n) O(n)
-
空間複雜度:構建了
next
陣列。複雜度為 O ( n ) O(n) O(n)
最後
這是我們「刷穿 LeetCode」系列文章的第 No.28
篇,系列開始於 2021/01/01,截止於起始日 LeetCode 上共有 1916 道題目,部分是有鎖題,我們將先將所有不帶鎖的題目刷完。
在這個系列文章裡面,除了講解解題思路以外,還會盡可能給出最為簡潔的程式碼。如果涉及通解還會相應的程式碼模板。
由於 LeetCode 的題目隨著周賽 & 雙週賽不斷增加,為了方便我們統計進度,我們將按照系列起始時的總題數作為分母,完成的題目作為分子,進行進度計算。當前進度為 28/1916
。
為了方便各位同學能夠電腦上進行除錯和提交程式碼,我在 Github 建立了相關的倉庫:https://github.com/SharingSource/LogicStack-LeetCode。在倉庫地址裡,你可以看到系列文章的題解連結、系列文章的相應程式碼、LeetCode 原題連結和一些其他的優選題解。
為了方便各位同學能夠電腦上進行除錯和提交程式碼,我建立了相關的倉庫:Github 地址 & Gitee 地址。
在倉庫地址裡,你可以看到系列文章的題解連結、系列文章的相應程式碼、LeetCode 原題連結和一些其他的優選題解。
#演算法與資料結構
#LeetCode題解
#演算法面試