【Leetcode刷题指南】字符串匹配问题之实现 strStr

【Leetcode刷题指南】字符串匹配问题之实现 strStr,第1张

CSDN话题挑战赛第1期
活动详情地址:https://marketing.csdn.net/p/bb5081d88a77db8d6ef45bb7b6ef3d7f
参赛话题:Leetcode刷题指南
话题描述:代码能力是一个程序员的基本能力,而除了做项目之外,大家接触到的最常规的提升代码能力的方法基本就是刷题了,因此,加油刷题,冲刺大厂!
创作模板:Leetcode刷题指南


文章目录
  • 💎一、实现 strStr()
    • 🏆1.题目描述
    • 🏆2.原题链接
  • 💎二、解题报告
    • 🏆1.思路分析
    • 🏆2.代码详解
      • 方法一:暴力遍历
      • 方法二:Rabin-Karp 算法
      • 方法三:KMP算法
    • 🏆3.KMP


💎一、实现 strStr() 🏆1.题目描述

判断一个字符串是不是另一个字符串的子串,子串出现的第一个位置。不存在就返回-1
输入:haystack = “hello”, needle = “ll”
输出:2

🏆2.原题链接

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

💎二、解题报告 🏆1.思路分析

🔑思路1:最简单的方法就是暴力遍历,遍历haystack 所有长度和needle 相同的子串, 时间复杂度O(n * m)

找子串这么经典的字符串匹配问题,怎么能只会暴力遍历呢?

🔑思路2:Rabin-Karp算法, 具体算法原理,已经更多练习可以看我这篇博文:https://blog.csdn.net/weixin_44179010/article/details/122081259

终极经典,不好记,不好理解,但是却很牛逼的算法。

🔑思路3:KMP算法, 等会会给出详解

🏆2.代码详解 方法一:暴力遍历

借助两个库函数可以拿到100%, 但是原因是测试用例的问题。 这个时间复杂度O(m * n) 还是比较大的

        for(int i = 0; i <= haystack.length() - needle.length(); i++) {
            if(haystack.substring(i, i + needle.length()).equals(needle)) return i;
        }
        return -1;
方法二:Rabin-Karp 算法

主要原理是计算子串Hash值,然后以O(n)的时间复杂度获取到主串长度为m的子串的hash值,hash值相同再比较每个字符是否相同。时间复杂度O(n + m)。 时间100%
代码可能较长,但都很简单,很好理解

    public int strStr(String haystack, String needle) {
        //Rabin - karp
        int MOD = 100000009;
        int base = 31;  //小写字母共26个,必须是比26大的映射。 选择质数31降低偶然性
        int srcLen = haystack.length(), tarLen = needle.length();
        //计算最高位权重, 这个必须用 long 防止溢出
        long highWeight = 1;  
        //注意这里只需要乘tarLen - 1 次就行了
        for(int i = 0; i < tarLen - 1; i++) {
            highWeight = (highWeight % MOD * base) % MOD;
        }

        //计算子串hash值
        long tarHash = 0;
        for(int i = 0; i < tarLen; i++) {
            tarHash = (tarHash * base % MOD + (needle.charAt(i) - 'a')) % MOD;
        }
        //System.out.println("highWeight=" + highWeight + ", tarHash=" + tarHash);
        //遍历计算主串长度和子串相同的 hash值
        long srcHash = 0;
        for(int i = 0; i < srcLen; i++) {
            srcHash = (srcHash * base % MOD + (haystack.charAt(i) - 'a')) % MOD;
            //System.out.println(srcHash);
            if(i >= tarLen - 1) {
                if(srcHash == tarHash) {
                    //hash值相同,逐个字母比较
                    boolean flag = false;
                    for(int j = 0; j < tarLen; j++) {
                        if(haystack.charAt(i - tarLen + 1 + j) != needle.charAt(j)) flag = true;;
                    }
                    if(!flag) return i - tarLen + 1;
                }
                //减去最高位的
                srcHash = (srcHash - highWeight * (haystack.charAt(i - tarLen + 1) - 'a') % MOD) % MOD;
                if(srcHash < 0) srcHash += MOD;
            }
        }
        return -1;
    }
方法三:KMP算法

待补充…

🏆3.KMP

KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。
核心是next数组, next数组包含的是前缀字符串 和 后缀后缀字符串相同的最大长度


CSDN话题挑战赛第1期
活动详情地址:https://marketing.csdn.net/p/bb5081d88a77db8d6ef45bb7b6ef3d7f

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/916025.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-16
下一篇 2022-05-16

发表评论

登录后才能评论

评论列表(0条)

保存