串是由零个或多个字符组成的有限序列,又名字符串。如let str="数据结构--串"是一个长度为7的串,其中'数据结构'相当于是str的字串

串的比较

    两个数字很好做出比较,1<2一眼就能对比出来。但是对于字符而言,却很难一眼变出'真伪'。如字符'王'和字符'我',正常人谁一眼能做得比较呢。(当然,在JavaScript中,已经帮我们处理好了两个字符的大小比较)

        即使是字符'a'和字符'b',按照一般的理解,可能也是认为谁在前谁大吧?

    显然,它们遵循着一定的比较规则,即ascii/unicode

    现在我们知道了,对于长度为1的串它们的比较规则是先转为编码后比较大小。那么对于长度大于1的串而言,理论上应该就是进行遍历,依次比较其大小

    现假设有串'123'和串'1234',显而易见的是,前三位'123'比较的结果一定是相等的,对于第二个串多出的'4'又该怎么比较呢?我觉得可以这样,将第一个串进行空串补位,为'123 '。假设这样是成立的,那么实际比较的结果就是' '和'4'的charCodeAt的大小,即

        前人已经帮我们总结出了定理:当两个串:s='a1a2...an',t='b1b2...bm',满足以下条件之一时,s

            :n

            :存在某个k<=min(m,n),使得ai=bi,且ai+1

        javascript实现如下

            我是这么想的,第一步,通过双层for...in循环拿到两个字符串相等的字串的临界点,之后分别就两种s

串的模式匹配算法

    假设现在有串"wyf是个不折不扣的渣男",希望从中找出子串"渣男"的位置。显然可以通过两层for'循环来逐个对比,相等时则将记录值加一即可,否则就退回的主串的下一个字串的初始位置。实现如下

(对于当前串而言,匹配的位置为10;只有子串匹配结束才表示有匹配结果,由于匹配到后i会再次加1,因此实际的位置是在匹配结果的下一个下标处,使用它向前移动子串的长度即查找到的最初匹配位置  ; i-j+1:由于每次只要存在匹配结果,那么i和j就一定是同步加一的,那么回退的时候就需要回退j,即本轮i增加的值 )

更高效的KMP算法

    一般的匹配算法可以满足大部分情况了,从lovely中找el只需要查找一次,最多也不过是m+n次,因为每次的首字母就是不匹配的。但是考虑一种极端的值,如主串"0000000001"中查找"001",那么就必须查找(10-2)*3 = 24次,即(m-n+1)*n,这是因为前七次都是在字串的位置3处匹配不到,即匹配了(m-n)*3次,后边在第八次时执行了三次匹配到,即(m-n)*3+3

    那么有没有一种方式可以一定程度是避免前七次的浪费呢?答案是kmp。在该模式下,不在回溯i,只动态改变j的值即可

    先看个示例对比,看能把不能找到不同点

    假设有串'000001和子串'01',在一般匹配模式下,过程大概是这样的——(字串无重复)

        第一次:取i=0,j=0,t[0]和s[0]相等,i++,j++,此时不等,j置为0,i停在1

        第二次:取i=1,j=0,t[1]和s[0]相等,i++,j++,此时不等,j置为0,i停在2

        第三次:取i=2,j=0,t[2]和s[0]相等,i++,j++,此时不等,j置为0,i停在3

        ...

        第n-1次:取i=n-1,j=0,t[n-1]和s[0]相等,i++,j++

        第n次:取i=n,j=0,t[n]和s[1]相等,i++,j++,超出边界,跳出循环

        (i由0到主串长度n,j由0到1来回切换

    假设有串'abcaxabcab'和子串'abcab',在一般匹配模式下,过程大概是这样的——(字串重复)

         第一次:取i=0,j=0,t[0]和s[0]相等,i++,j++,t[1]和s[1]相等,...,t[4]和s[4]不等,i++,j置为0

        第二次:取i=1,j=0,t[1]和s[0]不等,j置为0,i++

        第三次:取i=2,j=0,t[2]和s[0]不等,j置为0,i++,此时i=3

        第四次:取i=3,j=0,t[3]和s[0]相等,i++,j++,t[4]和s[1]不等,i++,j置为0

        第五次:取i=4,j=0,t[4]和s[0]不等,i++,j置为0

        第六次:取i=5,j=0,t[5]和s[0]相等,i++,j++,t[6]和s[1]相等,...,t[9]和s[4]相等,匹配结束

        (i的变化为:0-1-2-3-4-1-2-3-4-5-6-7-8-9;j的变化为:0-1-2-3-4-0-0-0-1-0-0-1-2-3-4

        到目前为止,比较明显的不同是,当子串中有重复字符时,i的变化会出现"回退"现象。又,在第一次时,abcax和abcab的前四个字符已经对应位置一一比较相等了,且a和a相等,故abca是不需要在次对比了的。故第四次的前半步即t[3]和s[0]的对比是可以跳过的,故,j应该为1。另外,而最后一个字符是没法跳过的,因为,abcaa和abcab,虽然满足了前四位一一对应相等,但是a和a是相等的,故i直接到4,即0-1-2-3-4-5-6-7-8-9,相应的j:0-1-2-3-4-0-1-2-3-4

        通过分析,我们知道,不管字串是否重复,都可以使i的变化保持一致。那么重点就是看j的变。本次我们将串做下修改,重新变成查找不重复的串,来看下区别。即

    假设有串'abcaxabcd'和子串'abcd'

        第一次:取i=0,j=0,t[0]和s[0]相等,i++,j++,t[1]和s[1]相等,...,t[3]和s[3]不等,i++,j置为0

        第二次:取i=1,j=0,t[1]和s[0]不等,j置为0,i++

        第三次:取i=2,j=0,t[2]和s[0]不等,j置为0,i++,此时i=3

        第四次:取i=3,j=0,t[3]和s[0]不等,i++,j置为0

        ...

        第六次:取i=5,j=0,t[5]和s[0]相等,i++,j++,j置为0,t[6]和s[1]相等,...,t[8]和s[3]相等,匹配结束

        可以看到,在第四次时,j值没有变化为1。而1的位置对应的字符即b。也就是说,在重复的子串abca中,j为1即跳过了子串a和串a的对比

        那理论上可以推断,在一轮对比的j-1的子串字符中,重复的个数即为j需要跳过的对比次数。如abcabd,重复个数为2,那么j需要跳过2个字符,若为abcabcf,则需要跳过3个字符

     JavaScript实现如下

    j值的变化推导公式如下

    则改进后的代码如下

    

你可能感兴趣的:(串)