1. 程式人生 > 其它 >【每日演算法/刷穿 LeetCode】28. 實現 strStr()(簡單)

【每日演算法/刷穿 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 ,將 subpp 做對比:

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(nm),構造和比較字串的複雜度為 O ( n ) O(n) O(n)。整體複雜度為 O ( ( n − m ) ∗ n ) O((n - m) * n)

    O((nm)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題解
#演算法面試

宮水三葉的刷題日記