算法之暴力破解和kmp算法 判断A字符串是否包含B字符串
我们都知道java中有封装好的方法,用来比较A字符串是否包含B字符串
如下代码,contains,用法是 str1.contains(str2), 这个布尔型返回,存在返回true,不存在返回false
还有indexOf,用法和contains一致,返回值是int,存在则返回对应的位置,注意位置从0开始的,不存在返回-1
public class Test { public static void main(String[] args) { String source = "abacaabacabacabaabb";
String pattern = "abacab";
System.out.println(source.contains(pattern) ); //true
System.out.println(source.indexOf(pattern) ); //
}
}
这两个方法的具体实现,是在java.lang包中,最终类String下
public boolean contains(CharSequence s) {
return indexOf(s.toString()) > -1;
}
contains其实调用了indexOf
public int indexOf(String str) {
return indexOf(str, 0);
}
public int indexOf(String str, int fromIndex) {
return indexOf(value, 0, value.length,
str.value, 0, str.value.length, fromIndex);
}
static int indexOf(char[] source, int sourceOffset, int sourceCount,
char[] target, int targetOffset, int targetCount,
int fromIndex) {
if (fromIndex >= sourceCount) {
return (targetCount == 0 ? sourceCount : -1);
}
if (fromIndex < 0) {
fromIndex = 0;
}
if (targetCount == 0) {
return fromIndex;
} char first = target[targetOffset];
int max = sourceOffset + (sourceCount - targetCount); for (int i = sourceOffset + fromIndex; i <= max; i++) {
/* Look for first character. */
if (source[i] != first) {
while (++i <= max && source[i] != first);
} /* Found first character, now look at the rest of v2 */
if (i <= max) {
int j = i + 1;
int end = j + targetCount - 1;
for (int k = targetOffset + 1; j < end && source[j]
== target[k]; j++, k++); if (j == end) {
/* Found whole string. */
return i - sourceOffset;
}
}
}
return -1;
}
如果你没有去看java中自带的实现,要你自己写方法实现呢
这就涉及到了算法:算法就是你的思路=======
第一步: 先构思一下思路,我要怎么去比较;一般人的思路是:
我拿后者的第一个字符,去看前者中是否含有,如果米有,一定不匹配;
我拿后者的第一个字符,去看前者中是否含有,如果前者中含有,继续查看,第二个字符是否和长串中接下来的一个字符相等
相等,继续向下匹配(如下图一)
不相等,重新用后者的第一个字符再和长字符串接下来一位进行比较
何谓接下来一位呢【假设abcdefgh和ddd,第一次比配到长字符串的第四位相等,第二次和长字符串的第5位开始比较,如下图二】
public class Force { /**
* 暴力匹配
* 时间复杂度为O(n*m);n为主串长度,m为模式串长度
算法的基本思想:
从主串的起始位置(或指定位置)开始与模式串的第一个字符比较,若相等,则继续逐个比较后续字符;
否则从主串的下一个字符再重新和模式串的字符比较。
依次类推,直到模式串成功匹配,返回主串中第一次出现模式串字符的位置,或者模式串匹配不成功,返回不成功,实际中可将返回值设置为int,不成功返回-1,成功返回0;
* @param source
* @param pattern
* @return
*/
public static String bruteForceStringMatch(String source, String pattern) {
int slen = source.length();
int plen = pattern.length();
char[] s = source.toCharArray();
char[] p = pattern.toCharArray();
int i = 0;
int j = 0; if (slen < plen)
return "你瞧瞧主串长度小于模式串,怎么可能啊,匹配失败"; // 如果主串长度小于模式串,直接返回-1,匹配失败
else {
while (i < slen && j < plen) {
if (s[i] == p[j]) // 如果i,j位置上的字符匹配成功就继续向后匹配
{ System.out.println(i+ "的值是"+ s[i] );
System.out.println(j + "的值是"+ p[j]);
++i;
++j; } else { System.out.println("我是else下的" + i + "的值是"+ s[i] );
System.out.println("我是else下的" + j + "的值是"+ p[j]);
i = i - (j - 1); // i回溯到主串上一次开始匹配下一个位置的地方
j = 0; // j重置,模式串从开始再次进行匹配
}
}
if (j == plen) // 匹配成功
return "位置是"+(i+1 - j);
else
return "匹配失败"; // 匹配失败
}
} }
查看匹配结果:
这是暴力破解,abcdeddd和ddd,在ddd的第0位和abcdeddd的第3位匹配后,继续比较下一位,发现不匹配了,重新将ddd的第0位和
kmp的思路如下:
KMP算法
KMP算法是D.E.Knuth、V.R.Pratt和J.H.Morris同时发现,所以命名为KMP算法。
此算法可以在O(n+m)的时间数量级上完成串的模式匹配。
主要就是改进了暴力匹配中i回溯的操作,KMP算法中当一趟匹配过程中出现字符比较不等时,
不直接回溯i,而是利用已经得到的“部分匹配”的结果将模式串向右移动(j-next[k])的距离。
import java.util.Arrays; public class kmp { /**
* KMP算法
KMP算法是D.E.Knuth、V.R.Pratt和J.H.Morris同时发现,所以命名为KMP算法。
此算法可以在O(n+m)的时间数量级上完成串的模式匹配。
主要就是改进了暴力匹配中i回溯的操作,KMP算法中当一趟匹配过程中出现字符比较不等时,
不直接回溯i,而是利用已经得到的“部分匹配”的结果将模式串向右移动(j-next[k])的距离。 * @param source
* @param pattern
* @return
*/
public static String kmpStringMatch(String source, String pattern)
{
int i = 0;
int j = 0;
char[] s = source.toCharArray();
char[] p = pattern.toCharArray();
int slen = s.length;
int plen = p.length;
int[] next = getNext(p); while(i < slen && j < plen)
{
if(j == -1 || s[i] == p[j])
{
++i;
++j;
}
else
{
//如果j != -1且当前字符匹配失败,则令i不变,
//j = next[j],即让pattern模式串右移j - next[j]个单位
j = next[j];
}
} if(j == plen)
return "位置是"+(i+1 - j);
else
return "匹配失败"; // 匹配失败
} /**
* 关于next[k]数组的计算引出的两种办法,一种是递归,一种对递归优化,第一种对应的就是KMP算法,第二种就是优化的KMP算法。
next函数值仅取决于模式串本身而和主串无关。
有很多讲next函数值计算办法的资料,在此我想用一种直观的比较容易理解的办法来表达。
举个栗子:现在有一个模式串abab 模式串的各个字串 前缀 后缀 最大公共元素长度
a null null 0
ab a b 0
aba a,ab a,ba 1
abab a,ab,aba b,ab,bab 2
* @param p
* @return
*/
private static int[] getNext(char[] p)
{
/**
* 已知next[j] = k, 利用递归的思想求出next[j+1]的值
* 1.如果p[j] = p[k],则next[j+1] = next[k] + 1;
* 2.如果p[j] != p[k],则令k = next[k],如果此时p[j] == p[k],则next[j+1] = k+1
* 如果不相等,则继续递归前缀索引,令k=next[k],继续判断,直至k=-1(即k=next[0])或者p[j]=p[k]为止
*/
int plen = p.length;
int[] next = new int[plen];
System.out.println("next函数值:" + Arrays.toString(next)); int k = -1;
int j = 0;
next[0] = -1; //这里采用-1做标识
while(j < plen -1)
{
if(k == -1 || p[j] == p[k])
{
++k;
++j;
next[j] = k;
}
else
{
k = next[k];
}
}
System.out.println("next函数值:" + Arrays.toString(next));
return next;
}
}
算法之暴力破解和kmp算法 判断A字符串是否包含B字符串的更多相关文章
- 字符串查找算法总结(暴力匹配、KMP 算法、Boyer-Moore 算法和 Sunday 算法)
字符串匹配是字符串的一种基本操作:给定一个长度为 M 的文本和一个长度为 N 的模式串,在文本中找到一个和该模式相符的子字符串,并返回该字字符串在文本中的位置. KMP 算法,全称是 Knuth-Mo ...
- 从暴力匹配到KMP算法
前言 现在有两个字符串:\(s1\)和\(s2\),现在要你输出\(s2\)在\(s1\)当中每一次出现的位置,你会怎么做? 暴力匹配算法 基本思路 用两个指针分别指向当前匹配到的位置,并对当前状态进 ...
- 【功能代码】---3 JS判断字符串是否包含某个字符串
JS判断字符串是否包含某个字符串 var str ="abc"; if(str.indexOf("bc")>-1){ alert('str中包含bc字符串 ...
- mysql判断表里面一个逗号分隔的字符串是否包含单个字符串、查询结果用逗号分隔
1.mysql判断表里面一个逗号分隔的字符串是否包含单个字符串 : FIND_IN_SET select * from tablename where FIND_IN_SET(传的参数,匹配字段) 例 ...
- C/C++判断字符串是否包含某个字符串
C风格 #include <iostream> #include <string> #include <cstring> using namespace std; ...
- 算法进阶面试题01——KMP算法详解、输出含两次原子串的最短串、判断T1是否包含T2子树、Manacher算法详解、使字符串成为最短回文串
1.KMP算法详解与应用 子序列:可以连续可以不连续. 子数组/串:要连续 暴力方法:逐个位置比对. KMP:让前面的,指导后面. 概念建设: d的最长前缀与最长后缀的匹配长度为3.(前缀不能到最后一 ...
- 算法(Java实现)—— KMP算法
KMP算法 应用场景 字符串匹配问题 有一个字符串str1 = " hello hello llo hhello lloh helo" 一个子串str2 = "hello ...
- 【字符串算法3】浅谈KMP算法
[字符串算法1] 字符串Hash(优雅的暴力) [字符串算法2]Manacher算法 [字符串算法3]KMP算法 这里将讲述 [字符串算法3]KMP算法 Part1 理解KMP的精髓和思想 其实KM ...
- 程序员的算法课(11)-KMP算法
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/m0_37609579/article/de ...
随机推荐
- 添加zookeeper到服务,并设置开机启动
一.先安装jdk jdk 路径为/usr/local/java 二.再安装zookeeper zk路径为/use/local/zookeeper 三.创建zookeeper脚本 cd /etc/rc. ...
- Ext.jsTree 向子节点添加叶子节点
// 定义搜索节点树结构Store const nodeStore = Ext.create('Ext.data.TreeStore', { autoLoad : true, id : 'nodeSt ...
- Django 数据库
一.操作数据库 Django配置连接数据库: 在操作数据库之前,首先先要连接数据库.这里我们以配置MySQL为例来讲解.Django连接数据库,不需要单独的创建一个连接对象.只需要在settings. ...
- ERNIE 2.0 理解与使用
更新中 更新时间:2019-12-06 17:43:27 实验需要,在自己学习的过程中做如下笔记,欢迎指正,欢迎交流. 1. ERNIE简述 ERNIE和BERT一样,也是基于transformer来 ...
- GB和GIB的区别
天啦撸,这么多年才知道这个东西! Gibibyte(giga binary byte)是信息或计算机硬盘存储的一个单位,简称GiB.由来“GiB”,“KiB”,“MiB”等是于1999年由国际电工协会 ...
- Python 面向对象总结
面向对象 类 class 类型 类变量 实例方法 init attack bite 类指针 - 指向父类 对象 对象指针 实例变量 self.name slef.age 组合 一个对象作为一个属性 s ...
- gcc/clang编译带pthread.h头文件的源码时需要的参数
今天敲了一个小程序,编译时出现错误:undefined reference pthread_create 原来由于pthread库不是Linux系统默认的库,连接时需要使用库libpthread.a, ...
- [转帖]阿里的JDK预热warmup过程
预热warmup过程 https://blog.csdn.net/wabiaozia/article/details/82056520 Jwarmup 原理是记录上一次运行时已经变成native co ...
- 使用idea上传项目初始化版本到coding
1.在coding创建项目 2.使用idea命令控制台初始化本地仓库 3.将代码提交到本地仓库,git add . 或者 git add <filename> 4.将本地仓库文件推送到co ...
- 解决maven项目无法读取src/main/java目录下面的配置文件问题
我们在用Mybatis去操作底层数据库的时候,需要用到xml配置文件,一般我们是把配置文件和dao放置在同一层目录. 但是在用idea操作maven项目的时候,我们可能会遇到无法读取到dao对应的ma ...