KMP演算法 Java實現

XFS小风發表於2024-04-17

Problem: 28. 找出字串中第一個匹配項的下標

目錄
  • 解題方法
  • 思路
    • 構建next陣列
    • 回溯查詢
  • 複雜度
  • Code

解題方法

  1. 構建next串
  2. 回溯查詢next串,最後下標

思路

  1. 透過最大字首字尾能找到下一次未查詢到後要回溯的位置

構建next陣列

無論如何第一個數的下一次回溯位置肯定是0,因此next[0]=0
這裡的 j表示字首起始位置 i表示字尾起始位置
如果找到字元不相同到的話,就讓他一直回溯找,並且回溯賦值j = next[j-1]
能找到相同字元的話就直接i++,j++,並且把next[i] = j
這裡先寫while判斷不相同 後寫相同,是因為不相同的終點
一定是有相同的字尾或者直接結束查詢(到了字串末尾)

回溯查詢

其實和上面的思路差不多,不能查詢相同字元就一直回溯,能的話就共同前進,直到j到了模式串長度
這時因為i也在前進,所以i的下標是 應該返回的下標+(匹配串的長-1)

複雜度

時間複雜度:

新增時間複雜度, 示例: $O(m+n)$

空間複雜度:

新增空間複雜度, 示例: $O(m)$

Code

class Solution {

    public int strStr(String haystack, String needle) {
        return new KMP(needle).search(haystack);
    }

    public class KMP {
        private String pattern;   // 模式串
        private int[] next;
        public KMP(String pattern){
            this.pattern = pattern;
            int m = pattern.length();
            // 建立next 陣列
            next = new int[m];
            next[0] = 0;
            for(int i = 1,j=0; i < m; i++){
                while(j>0&&pattern.charAt(i)!=pattern.charAt(j)){
                    j = next[j-1];
                }
                if(pattern.charAt(i) == pattern.charAt(j)){
                    j++;
                }
                next[i] = j;
            }
        }

        public int search(String text){
            int j = 0;
            for(int i=0;i<text.length();i++){
                while(j>0&&text.charAt(i) != pattern.charAt(j)){
                    j = next[j-1];
                }
                if(text.charAt(i) == pattern.charAt(j)){
                    j++;
                }
                if(j == pattern.length()){
                    return i-pattern.length()+1;
                }
            }
            return -1;
        }
    }

}

相關文章