一般提起字串的相關演算法,就是幾個基本的演算法:賦值strcpy、求長strlen、聯接strcat、比較strcmp和求子串substr。這5個操作相對來說都比較簡單,構成了字串的最小操作集,其他的演算法都可以由這幾個演算法來實現。但是實際應用中,模式匹配index是應用非常廣泛的字串操作,我們傾向於不依賴其他的操作來實現它。
如下圖,在目標字串s中查詢模式字串t的最直白的做法就是:
1.分別用i、j指向字串
2.依次遍歷,s[i]==t[j]則i++、j++
3.s[i]!=t[j]則i回溯到目標字串s的起始點開始比較,j回溯到t字串的起點
這個過程很容易寫成程式,如下:
/**
*功能: 在目標字串中求模式字串的位置
*引數: s——目標字串(source string)
t——模式字串(template string)
pos——目標字串從pos開始查詢
*返回: 查詢成功,返回t在s中的第乙個匹配位置
查詢失敗,返回-1
*其他: 2015/01/09 by jim wen ver1.0
**/int index( const char *s, const char *t, int pos )
else//查詢失敗
可以看到,1、2歩和一般匹配相同,不同的是第3歩,當s和t失配後,i並沒有回溯,這時候j回溯到a。為什麼這樣做呢,注意了!!!
對於t=abcabcdef,在d處失配後一定可以確定s對應的a之前的字串行一定是abcabc,也就是說不管s是什麼,只要t匹配到d,那麼一定可以確認s對應點之前的字串行,進一步也就是說不管s是什麼,只要t在d處失配,那麼一定可以根據t本身推出下一步應該使用t中的哪乙個字元和當前s的i處字元比較,決定失配後j的回溯位置的只是字串t。
我們可以把這個關係描述成j=next[j],即在j處失配後下乙個j的位置。利用這個關係,我們就可以大大優化程式執行過程,簡單來說就是發現s和t失配時,保持i不變,利用已有的關係計算新的j位置,這個過程中只有j產生回溯,這就是大名鼎鼎的kmp演算法。
那麼整個匹配過程如下:
1.分別用i、j指向字串
2.依次遍歷,s[i]==t[j]則i++、j++
3.s[i]!=t[j],則t向右滑動到j=next[j],繼續s[i]和s[j]的比較,如果不等則再繼續t向右滑動到j=next[j],繼續s[i]和s[j]的比較,如此迴圈
4.一旦t向右滑動的太厲害(即j=0時和s[i]還不匹配,則j只能=-1了),則i++、j++,此時j退無可退,必須增加i,否則會陷入死迴圈
那麼整個過程寫程式程式如下(注意過程2和4合併了),
/**
*功能: 在目標字串中求模式字串的位置
*引數: s——目標字串(source string)
t——模式字串(template string)
pos——目標字串從pos開始查詢
*返回: 查詢成功,返回t在s中的第乙個匹配位置
查詢失敗,返回-1
*其他: 2015/01/09 by jim wen ver1.0
**/int kmp_index( const char *s, const char *t, int pos )
else//查詢失敗
}
如下圖:
假設t[j]和s[i]失配,則下乙個應該比較的是t[k]和s[i],則必然有
又由已知的匹配關係有
則對於t必然有:
可以看到,j移動的規則就是找到從t1開始的一段字串行和tj前面的一段序列相同。
到這裡,就找到t的內部關係了,下面只用t計算next陣列:
如何計算next陣列呢?以t作為目標字串,同時以t作為模式字串,如下圖:
這裡引入了t-1,表示j向右滑到頭了,那麼計算next陣列和模式匹配的演算法就非常相似了,如下:
1.初始時i=0,j=-1,next[i]=j,即next[0]=-1,就是當t[0]和主串s不匹配的時候那麼這時候當前s[i]位置就是不匹配了
2.如果t[i]==t[j],
此時隱含t[i-1]=t[j-1],t[i-2]=t[j-2]......
那麼就有
此時當然有next[i+1]=j+1
3.如果t[i]!=t[j],注意此時隱含
那麼為了找到和ti相同的元素,向右滑動,求下乙個滿足條件的j
j=next[j]
4.向右滑動過頭,j=-1,則next[i+1]=j+1=0
5.補充在2中,如果t[i+1]==t[j+1],則
s和t[i+1]失配時,按照2有s再和t[next[i+1]]=t[j+1]匹配,顯然必然也是失配的,這時候必須再向下查詢,即next[i+1]=next[j+1]
那麼實際求取next的程式如下(合併2、4、5),是不是和模式匹配程式很相似呢?
void get_next( const char *t, int *next )
else
}else
}return;
}
13 字串查詢
對於乙個給定的 source 字串和乙個 target 字串,你應該在 source 字串中找出 target 字串出現的第乙個位置 從0開始 如果不存在,則返回 1。說明在面試中我是否需要實現kmp演算法?樣例如果 source source 和 target target 返回 1。如果 sou...
201409 3 字串匹配
試題編號 201409 3 試題名稱 字串匹配 時間限制 1.0s 記憶體限制 256.0mb 問題描述 問題描述 給出乙個字串和多行文字,在這些文字中找到字串出現的那些行。你的程式還需支援大小寫敏感選項 當選項開啟時,表示同乙個字母的大寫和小寫看作不同的字元 當選項關閉時,表示同乙個字母的大寫和小...
20140903 字串匹配
問題描述 試題編號 201409 3 試題名稱 字串匹配 時間限制 1.0s 記憶體限制 256.0mb 問題描述 問題描述 給出乙個字串和多行文字,在這些文字中找到字串出現的那些行。你的程式還需支援大小寫敏感選項 當選項開啟時,表示同乙個字母的大寫和小寫看作不同的字元 當選項關閉時,表示同乙個字母...