我们都知道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字符串的更多相关文章

  1. 字符串查找算法总结(暴力匹配、KMP 算法、Boyer-Moore 算法和 Sunday 算法)

    字符串匹配是字符串的一种基本操作:给定一个长度为 M 的文本和一个长度为 N 的模式串,在文本中找到一个和该模式相符的子字符串,并返回该字字符串在文本中的位置. KMP 算法,全称是 Knuth-Mo ...

  2. 从暴力匹配到KMP算法

    前言 现在有两个字符串:\(s1\)和\(s2\),现在要你输出\(s2\)在\(s1\)当中每一次出现的位置,你会怎么做? 暴力匹配算法 基本思路 用两个指针分别指向当前匹配到的位置,并对当前状态进 ...

  3. 【功能代码】---3 JS判断字符串是否包含某个字符串

    JS判断字符串是否包含某个字符串 var str ="abc"; if(str.indexOf("bc")>-1){ alert('str中包含bc字符串 ...

  4. mysql判断表里面一个逗号分隔的字符串是否包含单个字符串、查询结果用逗号分隔

    1.mysql判断表里面一个逗号分隔的字符串是否包含单个字符串 : FIND_IN_SET select * from tablename where FIND_IN_SET(传的参数,匹配字段) 例 ...

  5. C/C++判断字符串是否包含某个字符串

    C风格 #include <iostream> #include <string> #include <cstring> using namespace std; ...

  6. 算法进阶面试题01——KMP算法详解、输出含两次原子串的最短串、判断T1是否包含T2子树、Manacher算法详解、使字符串成为最短回文串

    1.KMP算法详解与应用 子序列:可以连续可以不连续. 子数组/串:要连续 暴力方法:逐个位置比对. KMP:让前面的,指导后面. 概念建设: d的最长前缀与最长后缀的匹配长度为3.(前缀不能到最后一 ...

  7. 算法(Java实现)—— KMP算法

    KMP算法 应用场景 字符串匹配问题 有一个字符串str1 = " hello hello llo hhello lloh helo" 一个子串str2 = "hello ...

  8. 【字符串算法3】浅谈KMP算法

    [字符串算法1] 字符串Hash(优雅的暴力) [字符串算法2]Manacher算法 [字符串算法3]KMP算法 这里将讲述  [字符串算法3]KMP算法 Part1 理解KMP的精髓和思想 其实KM ...

  9. 程序员的算法课(11)-KMP算法

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/m0_37609579/article/de ...

随机推荐

  1. 超详细的RNN代码实现(tensorflow)

    一.学习单步的RNN:RNNCell 如果要学习TensorFlow中的RNN,第一站应该就是去了解“RNNCell”,它是TensorFlow中实现RNN的基本单元,每个RNNCell都有一个cal ...

  2. ALBPM Service Config

    ALBPM Config About ALBPM Studio Msg , JSP and webResources together deploy services. Msg     "D ...

  3. 【c# 学习笔记】子类的初始化顺序

    使用了继承之后,当我们初始化一个子类时,除了会调用子类的构造函数外,同时也会调用基类的构造函数.子类的初始化顺序如下: ① 初始化类的实例字段: ② 调用基类的构造函数,如果没有指明基类,则调用Sys ...

  4. 做了一个非竞价排名、有较详细信息的程序员职位 match 网站

    作为一个程序员,每次看机会当我去 BOSS 直聘 或者拉勾网进行搜索时,返回的顺序并不是根据匹配程度,而是这些公司给 BOSS 直聘或者拉勾网付了多少钱.这种百度式的竞价排名机制并没有把我做为求职者的 ...

  5. mysql每次update数据,自动更新对应表中时间字段

    mysql 已经创建完成表的情况下, 使得其中的时间字段 在每次 uodate 数据的时候 自动更新事件, 运行如下sql ALTER TABLE tab_name MODIFY COLUMN upd ...

  6. Docker准备

    1. 引言 Docker是目前最流行的容器技术,是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的.可移植的.自给自足的容器.是开发人员和系统管理员使用容器开发,部署和运行应用程序的平台.也许我们 ...

  7. 封装Json+日志

    /** * 输出json * @param $msg * @param int $errno */ public function printOutError($msg = '操作失败', $errn ...

  8. Feign【开启GIZP压缩】

    SpringCloudFeign支持对请求和响应进行gzip压缩,以此来提高通信效率. 1.搭建gzip-demo工程 1.1.工程依赖: <parent> <groupId> ...

  9. centos7.6 yum安装mysql5.7版本

    由于mysql5.5及之前的版本一些项目上线报错 卸载: 首先删除centos上原来的mysql老版本,注意备份,清理干净. 之前怎么安装的清理,防止卸载不干净会有冲突. 我之前yum安装mysql5 ...

  10. python学习-19 字典

    字典dict 1.dic = {key:value,key:value} 字典有{ }括住,字典的value可以是任意值,字典的key的值不包括列表和字典 di = {"age": ...