【Leetcode】28. Implement strStr()

題目地址:

https://leetcode.com/problems/implement-strstr/

給定兩個字符串,判斷第二個是否是第一個的子串,如果是則返回匹配的起始地址,否則返回1-1

法1:暴力法。直接枚舉所有的開始位置,依次做匹配,一旦匹配成功則返回起始點下標,如果一直未成功則返回1-1。代碼如下:

public class Solution {
    public int strStr(String s, String p) {
        if (s == null || p == null) {
            return -1;
        }
        
        if (p.isEmpty()) {
            return 0;
        }
    	
    	// i後面要留足p的長度這麼多位置
        for (int i = 0; i + p.length() - 1 < s.length(); i++) {
        	// 開始從p[0]開始匹配
            int idx = 0;
            while (idx < p.length()) {
                if (s.charAt(i + idx) != p.charAt(idx)) {
                    break;
                }
                idx++;
            }
            
            // 匹配完了說明找到了子串,返回起始點下標
            if (idx == p.length()) {
                return i;
            }
        }
        
        return -1;
    }
}

時間複雜度O(nm)O(nm),空間O(1)O(1)

法2:KMP。KMP算法有一個next數組的概念,首先參考https://blog.csdn.net/qq_46105170/article/details/106168535,在未改進版本的KMP中,pp的next數組n[i]n[i]表示p[0:i1]p[0:i-1]中最長的相等前後綴的長度,而在改進版本中,n[i]n[i]則表示當p[i]p[i]s[j]s[j]不匹配的時候,pp裏下一個要與s[j]s[j]匹配的字符的下標。未改進版本的KMP中,這個下標取的是最長的相等前後綴的長度,利用這個信息去移動pp,可以在不錯過可能解的情況下,保證移動後和s[j]s[j]比較時,之前的字符已經全部相等,也就是不用再進行匹配了;但是它還可以利用一個信息,若移動後與s[j]s[j]對齊的那個字符仍然與p[i]p[i]相等,那麼肯定會出錯,還是得繼續向後移,改進的KMP算法就是將這個信息加入進去。首先,若s[j]p[i]s[j]\ne p[i],那麼下一個與s[j]s[j]對齊的字符變爲了p[n[i]]p[n[i]],若還不等,則對齊的是p[n[n[i]]]p[n[n[i]]],直到相等或者變爲1-1爲止。如果我們已經知道了p[i]=p[n[i]]p[i]=p[n[i]],那再次對齊就沒有意義,因爲還要取一次next。所以索性在一開始就”next到底“,杜絕p[i]=p[n[i]]p[i]=p[n[i]]的情況發生。代碼如下:

public class Solution {
    public int strStr(String s, String p) {
        if (s == null || p == null) {
            return -1;
        }
        
        if (p.isEmpty()) {
            return 0;
        }
        
        int i = 0, j = 0;
        int[] next = buildNext(p);
        while (i < s.length() && j < p.length()) {
            if (j == -1 || s.charAt(i) == p.charAt(j)) {
                i++;
                j++;
            } else {
                j = next[j];
            }
        }
        
        return j == p.length() ? i - j : -1;
    }
    
    private int[] buildNext(String p) {
        int[] next = new int[p.length()];
        int i = 0, j = next[0] = -1;
        while (i < p.length() - 1) {
            if (j == -1 || p.charAt(i) == p.charAt(j)) {
                i++;
                j++;
                // 在未改進的KMP算法中,next[i]直接取j;
                // 在改進的算法中需要判斷一下當前字符是否和p[j]相等,如果相等則還需要next一下
                next[i] = p.charAt(i) == p.charAt(j) ? next[j] : j;
            } else {
                j = next[j];
            }
        }
        
        return next;
    }
}

時間複雜度O(n+m)O(n+m),空間O(m)O(m)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章