28. Implement strStr()

題目描述:實現(xiàn)strStr()函數(shù),返回子串第一次出現(xiàn)的位置,未出現(xiàn)則返回-1。如:

Input: haystack = "hello", needle = "ll"
Output: 2
Input: haystack = "aaaaa", needle = "bba"
Output: -1

分析:暴力算法時間復(fù)雜度O(m*n),更高效的可以用KMP、各種文本編輯器的"查找"功能大多采用的Boyer-Mooer、Rabin-Karp算法。

暴力法:即母串與子串一個字符一個字符比對,外層循環(huán)對母串遍歷haystack.size() - needle.size()遍,即子串第一個字符與母串的第幾個字符對齊,內(nèi)層循環(huán)遍歷子串各字符,看是否都與母串相應(yīng)位置字符相同。

class Solution {
public:
    int strStr(string haystack, string needle) {
        int m = haystack.size();
        int n = needle.size();
        int i, j;
        for (i = 0; i <= (m - n); i ++)
        {
            for (j = 0; j < n; j ++)
                if (haystack[i + j] != needle[j])
                    break;
            if (j == n)
                return i;
        }
        return -1;
    }
};

KMP法:為保證只對母串進(jìn)行一次遍歷,要記錄子串的next數(shù)組,即當(dāng)子串的某一位與母串不匹配時應(yīng)該用子串前面的哪一位來重新對應(yīng)母串的該字符。主要理解getnext函數(shù)。因為主串不回溯,next數(shù)組已提前計算,故時間復(fù)雜度O(n)。

class Solution {
public:
    int strStr(string haystack, string needle) {
        int m = haystack.size();
        int n = needle.size();
        if (n == 0)
            return 0;
        else if(m == 0)
            return -1;
        
        int next[n];
        getnext(needle, next);
        int i = 0, j = 0;
        while (i < m && j < n)
        {
            if (j == -1 || haystack[i] == needle[j])
            {
                i ++;
                j ++;
            }
            else
            {
                j = next[j];
            }
        }
        if (j == n) return i - n;
        else return -1;
    }
    //獲取子串的next數(shù)組,只與子串有關(guān)。對模式串needle做“自匹配”,即求出模式串前綴與后綴中重復(fù)部分,將重復(fù)信息保存在next數(shù)組中
    void getnext(string &s, int next[])
    {
        int l = s.size();
        int i = 0, j = -1;
        next[i] = -1;
        while (i < l - 1)
        {
            if (j == -1 || s[i] == s[j])
            {
                i ++; j ++;
                next[i] = j;
            }
            else
                j = next[j];
        }
    }
};

Horspool算法簡易版Boyer-Mooer算法,只實現(xiàn)了壞字符規(guī)則,沒用好后綴規(guī)則。思路見參考,第一個樣例可正確輸出2,但在樣例"mississippi" "issipi"處超時。最壞情況下時間復(fù)雜度O(m*n)

class Solution {
public:
    int strStr(string haystack, string needle) {
        int m = haystack.size();
        int n = needle.size();
        if (n == 0)
            return 0;
        else if(m == 0)
            return -1;
        int i = n - 1, j = n - 1;
        while (j >= 0 && i < m)
        {
            if (haystack[i] == needle[j])
            {
                i --, j --;
            }
            else
            {
                i += dist(needle, haystack[i]);
                j = n - 1;
            }
        }
        if (j < 0) return i + 1;
        return -1;
    }
    
    int dist(string t, char c)
    {
        int l = t.length();
        int i = l - 1;
        if (t[i] == c)
            return l;
        
        i --;
        while (i >= 0)
        {
            if (t[i] == c)
                return l - 1 - i;
            else 
                i --;
        }
        return l;
    }
};

Karp-Rabin算法:這是一種一般情況下線性,最壞情況下O((n-m)*m)的算法。算法的主要思路是設(shè)計一種哈希函數(shù),將目標(biāo)字符串映射成一個值,然后在主串中遍歷每個與目標(biāo)串長度相同的子串,用同樣的哈希函數(shù)算其值,與目標(biāo)串的哈希值相比較。相等時還要再比較此子串的每個字符與目標(biāo)串的每個字符,因為哈希函數(shù)可能有沖突。

參考

Boyer-Mooer算法講解

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容