使用OC写算法之KMP算法

序言

当简友们看到这篇文章的时候,我默认大家都已经了解过BF算法了,如果有对BF算法不了解的,建议可以先看下我上一篇文章:传送门

KMP简介

KMP简单来说是三位大牛:D.E.Knuth、J.H.Morris和V.R.Pratt共同发现的,看到这三位大牛的名字,我想你应该明白为什么叫KMP算法了,KMP算法要解决的问题就是在字符串(也叫主串)中的模式(pattern)定位问题。说简单点就是我们平时常说的关键字搜索。模式串就是关键字(接下来称它为P),如果它在一个主串(接下来称为T)中出现,就返回它的具体位置,否则返回-1(常用手段)。

BF算法存在的问题以及KMP解决的问题

其实BF算法存在的问题和KMP要解决的问题本身是一个问题,因为KMP要解决的问题恰好就是BF算法所存在的问题,在上篇文章其实我就有介绍BF算法存在的问题,这里我还是再简单介绍一下吧:
首先我们先看下BF算法的实现代码:

 @param source 原字符串
 @param target 匹配字符串
 @return 成功返回索引 失败返回-1
 */
- (int)bruteForce2WithSource:(NSString *)source target:(NSString *)target {
    //主串索引
    int i = 0;
    //字串索引
    int j = 0;
    while (i < source.length && j < target.length) {
        //依次来一个一个对比
        if ([source characterAtIndex:i] == [target characterAtIndex:j]) {
            i++;
            j++;
        }else {//索引回溯 i的索引变化为下一个也就是 (i- j +1)而j = 0从头开始
            i = i - j + 1;
            j = 0;
        }
    }
    
    //到这一步 判断如果j == 字符串长度证明匹配成功
    if (j == target.length ) {
        return i - j;
    }
    return -1;
}

了解BF算法的人应该都知道有一个痛点,因为它的时间复杂度是M*N的,每一次匹配之后,当遇到匹配不成功的时候,又要重头开始去匹配,这是没有必要的,例如下面的例子:

image.png

很明显我们可以看到在这里C 和 D 无法匹配了,这时候如果按照BF算法的解法,我们理所当然就应该是拿A和B去匹配,这里很明显是没必要的,我们可以直接像下图一样匹配:

image.png

这里我就不用给大家证明为啥了吧,看不出来的一个一个试一下就清楚了,看到这里,我想大家应该知道KMP是为了解决一个什么问题了。

next数组的求法

大家都称这个存放j下一个匹配位置的数组叫做next,那我这里也就叫它next数组吧,从字面上来看 我们也知道,这个next数组其实就是存放下一个要匹配的位置,也就是要移动的位数,下面我们不废话直接上代码(有详细的注释 不要为难我去解释到底next数组到底怎么生成了好不好?):

/**
 获取next数组

 @param pString 匹配字符串
 @return next数组
 */
- (NSArray *)getNextArray:(NSString *)pString {
    NSMutableArray *nextA = [NSMutableArray arrayWithCapacity:pString.length];
    //定义前缀索引
    int j = -1;
    //定义后缀索引 大于前缀索引
    int i = 0;
    //给next数组的第0个元素赋值为-1
    nextA[0] = @(-1);
    while (i < pString.length) {
        if (-1 == j || [pString characterAtIndex:i] == [pString characterAtIndex:j]) {
            //当前缀和后缀相等时
            i++;
            j++;
            //给next数组的元素赋值
            nextA[i] = @(j);//这里说明一下 假设pString是 @"aba"  第0个元素的a 和 第2个元素的a相等 那么next[2]就应该是1 也就是要往后挪动一个位置
        }else {
            //当两个字符不相等的时候 我们就需要回溯 那具体回溯的位置是哪里呢? 一句next数组的概念 它里面存放的元素是下一次要移动的位数 所以我们的j = nextA[j]
            j = [nextA[j] intValue];
        }
        
    }
    
    return nextA;
}
KMP算法实现
#pragma  mark -  KMP算法
#pragma  mark -

/**
 KMP算法

 @param tString 主串
 @param pString 字串
 @return 匹配成功返回匹配成功位置 失败返回-1
 */
- (int)KMP:(NSString *)tString pString:(NSString *)pString {
    //主串tString的索引
    int i = 0;
    //字串pString的索引
    int j = 0;
    //获取主串和字串的字符串长度(特别注意因为使用length获取的长度是NSUInteger类型的,直接和它对比会出现问题 所以这里我都强制转换为int)
    int tLength = (int)tString.length;
    int pLength = (int)pString.length;
    //获取next数组
    NSArray *nextArray = [self getNextArray:pString];
    while (i < tLength && j < pLength) {
        if (-1 == j || [tString characterAtIndex:i] == [pString characterAtIndex:j]) {
            i++;
            j++;
        }else {
            //回溯到下一个位置
            j = [nextArray[j] intValue];
        }
    }
    if (j == pLength) {
        return i- j;
    }
    
    return -1;
}

我们可以看到这个和BF算法唯一不同的地方就是,在匹配失效的时候 j的索引位置不在是:

  i = i - j + 1;
  j = 0;

而是换成了从next数组来获取:

 //回溯到下一个位置
 j = [nextArray[j] intValue];

这样就把KMP算法的核心问题换成了怎么获取next数组,所以大家多多理解next数组的代码吧。有什么地方没有理解的可以留言。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容