文章目录

  • 一、字符串查找
  • 二、Rabin-Karp 算法

一、字符串查找


算法题目链接 : https://www.lintcode.com/problem/13/

在 一个字符串 中查找 另外一个字符串 第一次出现的位置 ;

如 : 在 “abcdefghijk” 中查找 “def” 第一次出现的位置 , 是 444 ;

该方法使用 暴力算法 , 两层 for 循环 , 肯定可以解决 ; 如果用暴力算法 , 那面试基本就凉了 ; 暴力算法的复杂度是 O(m×n)O(m \times n)O(m×n) , mmm 是第一个大字符串的长度 , nnn 是被查找的字符串长度 ;

KMP 算法 是专门用于解决该问题的算法 , 该算法 只能用于解决在一个字符串中查找另外一个字符串的问题 ; KMP 算法主要靠背诵 , 没有涉及到算法的理论 , 只能用于解决单一字符串查找问题 , 一般面试时不考虑使用该算法 ; KMP 算法的算法复杂度是 O(m+n)O(m + n)O(m+n) ;

Rabin-Karp 算法 比 KMP 算法更简单 , 其基本原理就是比较字符串的 哈希码 ( HashCode ) , 快速的确定子字符串是否等于被查找的字符串 ;

二、Rabin-Karp 算法


假设要在 “abcde” 字符串中 , 寻找字符串 “cde” ;

遍历时 , 如果使用蛮力算法遍历 , 先对比 “abc” 是否与 “cde” 相等 , 明显不等 ,
继续遍历 , 向右平移一位 , 对比 “bcd” 与 “cde” 是否相等 ;

这里从 “abc” 平移到 “bcd” , 如果使用整个字符串比较的话 , 假如字符串的位数是 nnn 位 , 则复杂度是 O(n)O(n)O(n) , 这里如果能将复杂度变为 O(1)O(1)O(1) , 那么时间复杂度将大大降低 ;

两个 nnn 位的字符串比较 , 那么需要逐位对比 , 时间复杂度是 O(n)O(n)O(n) , 这里使用哈希函数 , 对比两个字符串的哈希值 , 这样将时间复杂度降低为 O(1)O(1)O(1) ;

哈希函数 :
哈希函数可以将任何类型的数据 , 字符串 , 整型 , 字节等数据 , 转为整数 ;
哈希表是一个很大的数组 , 使用哈希函数 , 将某个字符串对应到哈希表中某个位置上 , 相同的字符串使用哈希函数计算的整数结果是相同的 ;

静置转换哈希函数 , 是最常用的哈希函数 ;
如 : “abcde” 的哈希码值为 a×314+b×313+c×312+d×311+e×310a \times 31^4 + b \times 31^3 + c \times 31^2 + d \times 31^1 + e \times 31^0a×314+b×313+c×312+d×311+e×310
313131 是一个魔法值 , 使用该值效率最高 , 一般都设置这个数 ; 整个公式类似于组合数学中的生成函数 ;
这个结果很大 , 可能超过整数表示范围 , 为该值模一个较大的数 , 模的数越大 , 冲突的概率就越小 ;
(a×314+b×313+c×312+d×311+e×310)mod106(a \times 31^4 + b \times 31^3 + c \times 31^2 + d \times 31^1 + e \times 31^0) \mod 10^6(a×314+b×313+c×312+d×311+e×310)mod106

哈希表计算 :

计算 “abcde” 的子字符串哈希值 ,
先计算 “abc” 的哈希值 xxx ,
然后计算 “abcd” 的哈希值 (x×31+d)mod106(x \times 31 + d) \mod 10^6(x×31+d)mod106 , 然后将 “a” 的哈希值减掉 , (x×31+d−a×313)mod106(x \times 31 + d - a \times 31^3) \mod 10^6(x×31+d−a×313)mod106 ;

这样就可以在 O(1)O(1)O(1) 的时间内 , 得到 “abc” 的哈希值 , 然后在 O(1)O(1)O(1) 的事件内得到 “bcd” 的哈希值 ;
被查找的字符串 “cde” 的哈希值是不变的 , 可以在开始计算出来 ;

这里注意 , 哈希值相等 , 并不是代表字符串完全相等 , 理论上讲 , 有可能存在哈希值相等 , 字符串不相等的时候 , 虽然概率及其微小 , 建议在哈希值相等的情况下 , 再次判定一次字符串是否相等 ;

哈希码不同 , 则字符串一定不同 ;
哈希码相同 , 字符串不一定相同 ;

遍历 mmm 次 , 用于遍历外层字符串索引 , 哈希值计算复杂度为 O(1)O(1)O(1) ,
那么 整体复杂度是 O(m)O(m)O(m) ,
只有在哈希值相等的时候 , 才遍历 nnn 个子字符串 , 复杂度是 O(n)O(n)O(n) ,
那么该算法的 整体时间复杂度是 O(m+n)O(m + n)O(m+n) ;

class Solution {/*** @param source:* @param target:* @return: return the index*/public int strStr(String source, String target) {if (target == null || source == null) {// 不符合规则, 直接返回 -1return -1;}// 计算哈希码int base = 1000000;int m = target.length();if (m == 0) {return 0;}// 计算 31^mint power = 1;for (int i = 0; i < m; i++) {power = (power * 31) % base;}// 计算被查找字符串哈希值int targetCode = 0;for (int i = 0; i < m; i++) {targetCode = (targetCode * 31 + target.charAt(i)) % base;}// 循环主体int hashCode = 0;for (int i = 0; i < source.length(); i++) {// 注意遍历的 i 用于计算哈希值// 哈希值代表的字符串的起始位置是 i - m + 1hashCode = (hashCode * 31 + source.charAt(i)) % base;// 如果不足 m 个字符, 不执行后续操作if (i < m - 1) {continue;}// 大于 m 个字符需要减去首位的哈希值if (i > m - 1) {hashCode = hashCode - (power * source.charAt(i - m)) % base;// 确保相减的结果是正数if (hashCode < 0) {hashCode += base;}}if (hashCode == targetCode) {// 双重验证if (source.substring(i - m + 1, i + 1).equals(target)) {return i - m + 1;}}}return -1;}
}class Main {public static void main(String[] args) {int index = new Solution().strStr("mabcban", "cb");System.out.println(index);}
}

【字符串】字符串查找 ( Rabin-Karp 算法 )相关推荐

  1. C++Rabin Karp算法字符串快速查找(附完整源码)

    C++Rabin Karp算法字符串快速查找 C++Rabin Karp算法字符串快速查找完整源码(定义,实现,main函数测试) C++Rabin Karp算法字符串快速查找完整源码(定义,实现,m ...

  2. Rabin Karp 算法详解及Python实现

    目录 一.Rabin Karp 核心思路 二.字符串如何做哈希映射 三.借助前缀和列表计算滑动窗口 四.leetcode28. 代码实现 Rabin Karp 算法是用于实现字符串的模式匹配,先看le ...

  3. leetcode 1044. Longest Duplicate Substring | 1044. 最长重复子串(Rabin Karp算法)

    题目 https://leetcode.com/problems/longest-duplicate-substring/ 题解 这题暴力超时,看了 Related Topics,以及 Hint,主要 ...

  4. SPOJ Substring Problem(Rabin Karp TLE)

    给出一个文本串及n个模式串,检查对应的模式串是否在文本串中出现 使用rabin karp算法超时 代码见: https://github.com/wuli2496/OJ/blob/master/spo ...

  5. Go 语言实现字符串匹配算法 -- BF(Brute Force) 和 RK(Rabin Karp)

    今天介绍两种基础的字符串匹配算法,当然核心还是熟悉一下Go的语法,巩固一下基础知识 BF(Brute Force) RK(Rabin Karp) 源字符串:src, 目标字符串:dest: 确认des ...

  6. java对字符串快查找_字符串快速查找 - Trie算法

    Trie算法 先对给定的字符串进行归集,形成一个多叉树形结构. 使用字符导航方式作匹配查找. trie算法有很多变种,以最左(前缀)匹配为例进行说明. 优点 使用字符导航查找方式,能最大限度减少字符比 ...

  7. Rabin-Karp 算法(字符串快速查找)

    Rabin-Karp 算法(字符串快速查找) 算法 代码 算法 Go 语言的 strings 包(strings.go)中用到了 Rabin-Karp 算法.Rabin-Karp 算法是基于这样的思路 ...

  8. java 类数组_Java常用类-字符串、日期类、算法及数组工具类等

    大家好,乐字节的小乐又和大家见面了.这次要给大家讲述的是Java常用类. 主要有以下知识点: Ø 字符串相关类(String .StringBuffer.StringBuilder) Ø 算法及数组工 ...

  9. python 正则表达式判断字符串是否为回文_JS使用栈判断给定字符串是否是回文算法示例...

    本文实例讲述了JS使用栈判断给定字符串是否是回文算法.分享给大家供大家参考,具体如下: /*使用栈stack类的实现*/ function stack() { this.dataStore = []; ...

  10. hiho1482出勤记录II(string类字符串中查找字符串,库函数的应用)

    string类中有很多好用的函数,这里介绍在string类字符串中查找字符串的函数. string类字符串中查找字符串一般可以用: 1.s.find(s1)函数,从前往后查找与目标字符串匹配的第一个位 ...

最新文章

  1. 人工智能行业有哪些岗位_建筑行业年薪超50万,哪些岗位有希望达到?你是什么岗位呢?昆山建造师培训学校...
  2. 中国半导体最强助攻来了!十年免税、上下游一揽子扶持,明确「集成电路」为一级学科...
  3. [官网]Prevent a worm by updating Remote Desktop Services (CVE-2019-0708)
  4. 捉虫记 单步跟踪 条件断点 变量查看实践
  5. 一起谈.NET技术,通过16道练习学习Linq和Lambda
  6. Visual Studio容器项目工程化心得
  7. python的内存回收机制_关于python的变量使用回收机制
  8. 使用^、(异或、并且)位运算 实现算数加法(+)
  9. sql oracle 递归查询语句,深入sql oracle递归查询
  10. spring配置线程池
  11. redhat7.2 修改centos yum源
  12. 序列二次规划——SQP
  13. 自动化专业好找工作吗?就业方向是什么?
  14. 问题:为什么在CAD中使用贱人工具箱中的递增命令会显示失败?
  15. 数字图像处理的发展历史、应用领域、主要来源
  16. 华三模拟器:IPV6路由实验
  17. 解读老黄历--月日时令
  18. 前端换肤功能如何实现
  19. jquery实现下拉框
  20. layui解决数据表格右侧有空白现象

热门文章

  1. 冬天了,麦克风/话筒 有杂音 的原因!
  2. .net core mysql CodeFirst
  3. 零件库管理信息系统设计--part03:管理员登录部分设计
  4. CodeForces 671C - Ultimate Weirdness of an Array
  5. XTUOJ 1206 Dormitory's Elevator
  6. PHP文件包含漏洞原理分析和利用方法
  7. 算法学习:最小圆覆盖
  8. docker系列之file基本操作
  9. linux下yum包更新不了
  10. 服务器上装了安全狗后远程链接不上怎么解决