zoukankan      html  css  js  c++  java
  • 【LeetCode】28.实现strStr()(KMP算法)

    题目链接

    28. 实现 strStr()

    题目描述

    实现 strStr() 函数。
    给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回  -1。
    
    示例 1:
    输入: haystack = "hello", needle = "ll"
    输出: 2
    
    示例 2:
    输入: haystack = "aaaaa", needle = "bba"
    输出: -1
    

    解题思路

    1.Java内置函数

    2.BF暴力法

    3.滑动窗口

    利用substring函数从haystack依次截取与needle字符串相同长度的字符串,两者进行比较即可

    4.KMP算法

    KMP算法的核心就在于求解模式串的最长公共前后缀,且next数组中next[0]=-1,next[1]=0是确定的,next数组的意义在于当模式串当前字符与匹配串不匹配时,next数组值就是模式串指针的下一个位置,而不是和暴力方法一样,每次都从头开始!

    图解暴力以及KMP算法真的很清晰

    B站视频「天勤公开课」KMP算法易懂版

    B站视频 KMP算法Next数组讲解

    AC代码

    1.Java内置函数

    String haystack = "hellowordllo";
    String needle = "llo";
    System.out.println(haystack.lastIndexOf(needle));//9
    System.out.println(haystack.indexOf(needle));//2
    System.out.println(haystack.indexOf(needle,3));//9
    a.indexOf(String s) //从字符串a开始从前往后找到第一个与字符s匹配的子串,找到就返回匹配的子串的下标,否则返回-1
    a.indexOf(String s,int Fromindex)//从字符串a第Fromidnex个元素开始从前往后找到第一个与字符s匹配的子串,找到就返回匹配的子串的下标,否则返回-1
    a.lastIndexOf(String s)//从后往前找
    

    2.BF暴力法(超时)

    class Solution {
        public int strStr(String haystack, String needle) {
            if(haystack.equals(needle)) return 0;
            if(haystack.length() < needle.length()) return -1;
            for(int i = 0; i < haystack.length(); i++){
                int index = i;
                int cnt = 0;
                for(int j = 0; j < needle.length(); j++){
                    if(index < haystack.length() && needle.charAt(j) == haystack.charAt(index)){
                        index++;
                        cnt++;
                    }
                    else break;
                }
                if(cnt == needle.length()) return i;
            }
            return -1;
        }
    }
    

    3.滑动窗口

    class Solution {
        public int strStr(String haystack, String needle) {
            if(haystack.equals(needle)) return 0;
            if(haystack.length() < needle.length()) return -1;
            int h_len = haystack.length();
            int n_len = needle.length();
            for(int i = 0; i <= h_len-n_len; i++){
                String s = haystack.substring(i,i+n_len);
                if(s.equals(needle)) return i;
            }
            return -1;
        }
    }
    

    4.KMP算法

    //KMP算法的核心在于求解next数组
    
    class Solution {
    	//next数组计算方法1
        int[] getnext(String needle){
            int[] next = new int[needle.length()];
            next[0] = -1;
            int l = -1;
            int index = 0;
            while(index < needle.length() - 1){
                if(l == -1 || needle.charAt(l) == needle.charAt(index)){
                    l++;
                    index++;
                    next[index] = l;
                }else l = next[l];
            }
            return next;
        }
        
        //next数组计算方法2(个人觉得这个更好理解)
        int[] getnext(String needle){
            int[] next = new int[needle.length()+1];//避免出现needle = "a"的情况,
            //如果needle=”a",那next[1]属于非法访问,所以next数组大小为needle.length()+1;
            next[0] = -1;
            next[1] = 0;
            int k = 0;
            int i = 2
            while(i < needle.length()){
                if(needle.charAt(i-1)==needle.charAt(k)){
                    k++;
                    next[i] = k;
                    i++;
                }else if(k == 0){//needle=“abcdefg",针对此种特殊情况
                    next[i] = 0;
                    i++;
                }else{
                    k = next[k];//有点类似与回溯的味道,不理解就强行背诵。
                }
            }
            return next;
        }
        
        //next数组计算方法3(暴力法,不过一般都会超时,所以了解一下就好)
        int[] getnext(String needle){
            int[] next = new int[needle.length()+1];
            next[0] = -1;
            next[1] = 0;
            for(int i = 2; i < needle.length(); i++){
                for(int j = 1; j < i; j++){ //j表示最长公共前后缀的长度
                    if(needle.substring(0,j).equals(needle.substring(i-j,i-j+j))){
                        next[i] = j;
                    }
                }
            }
            return next;
        }
    
        public int strStr(String haystack, String needle) {
            if(haystack.length() == 0 && needle.length() == 0) return 0;
            if(haystack.length() == 0) return -1;
            if(needle.length() == 0) return 0;
            int h_len = haystack.length();
            int n_len = needle.length();
            int h_index = 0;
            int n_index = 0;
            int[] next = getnext(needle);
            while(h_index < h_len){
                if(haystack.charAt(h_index) == needle.charAt(n_index)){
                    h_index++;
                    n_index++;
                }else{
                    if(n_index == 0){//两个字符串首个元素不同,那匹配串指针肯定要加1呀
                        h_index++;
                    }else{
                        n_index = next[n_index];
                    }
                }
    			//当模式串指针到模式串末尾,证明匹配成功
                if(n_index == needle.length()) return h_index-n_index;
            }
            return -1;
        }
    }
    
  • 相关阅读:
    记录软件工程课程项目开发时遇到的各种小问题(django)
    用python实现逻辑回归
    利用KD树进行异常检测
    PyQt4入门学习笔记(五)
    PyQt4入门学习笔记(四)
    import matplolib 时出现"This probably means that tk wasn't installed properly."的解决方法
    IDEA上安装和使用checkstyle,findbugs,visualVM,PMD插件
    pycharm连接mysql数据库
    基于trie树做一个ac自动机
    用python实现最长公共子序列算法(找到所有最长公共子串)
  • 原文地址:https://www.cnblogs.com/XDU-Lakers/p/13562350.html
Copyright © 2011-2022 走看看