帶通配符*的字符串匹配

2. 如果不想用遞歸,可以考慮另外一種思路是

對於t,可以看成被一些*串(連續的*組成的子串)劃分成了一組跟s一樣純由字母組成的子串。
這樣問題就轉化成了在s中尋找一個子串序列。

  1. 開始時還像普通的串匹配一樣,移動s和t,直到t遇到第一個*
  2. 然後t後面的部分假設被*串劃分成如下一組字符字串:t1, t2, t3
  3. 那麼問題變成了從s的當前位置開始找t1,如果沒找到,則不匹配;如果找到(這時候有可能s中存在很多t1,我們只需考慮第一個。因爲如果第一個能導致整個串匹配成功,則已經達到我們的目的,其他的不用考慮,因爲我們並不需要輸出所有的匹配。而如果第一個都不能使整個串匹配成功,後面情況由於可供匹配的子串更短,更不可能成功。),則繼續從s匹配了t1的部分後面繼續找t2;如此操作直至所有的子串都找到時,則整個匹配成功,否則任何一處沒匹配則整個匹配失敗

爲了方便操作,開始時把s和t尾部相等的字符都截掉了。
Java源碼:

001 public static boolean isMatch(char[] s, char[] t) {
002         //cut off the tail of non-* characters
003         int i=s.length-1,j=t.length-1;
004         while(i>-1 && j>-1 && s[i] == t[j]) {
005             i--;
006             j--;
007         }
008  
009         int endS = i+1, endT = j+1;
010         i=j=0;
011         while(i<endS && j<endT && s[i] == t[j]) {
012             i++;
013             j++;
014         }
015         if(j==endT) {//t has no *
016             if(i==endS) {//t equals to s
017                 return true;
018             else {
019                 return false;//s is longer than t, unequal
020             }
021         }
022         if(t[j] != '*') {// not match for a non-* character
023             return false;
024         }
025         // the first * is found
026  
027         int subStringStart = j;
028         int subStringEnd = j;
029         while (j < endT) {
030             while (j < endT
031                     && t[j] == '*') {
032                 j++;
033             }
034             if(j==endT) {
035                 return true;
036             }
037             // get the first non-* char
038             subStringStart = j;
039  
040             while (j < endT
041                     && t[j] != '*') {
042                 j++;
043             }
044             // get the last non-* char
045             subStringEnd = j-1;
046  
047             //match it in s using normal string match algorithm
048             i = isNormalMatch(s, i, endS-1, t, subStringStart, subStringEnd);
049             if(i == -1) {
050                 return false;
051             else if(i==endS) {
052                 return true;
053             }
054         }
055  
056         // t ends as a non-* character but s not ends yet
057         return false;
058     }
059  
060     //KMP
061     private static int isNormalMatch(char[] text, int textStart, inttextEnd, char[] pattern, int patternStart, int patternEnd) {
062                 if(textStart>textEnd || patternStart > patternEnd) {
063                     return -1;
064                 }
065         char[] s1 = Arrays.copyOfRange(text, textStart, textEnd+1);
066         char[] s2 = Arrays.copyOfRange(pattern, patternStart, patternEnd+1);
067         int[] next = new int[patternEnd-patternStart+1];
068         caculateNext(s2,next);
069         int i = isMatch(s2,s1,next);
070         if(i != -1) {
071             i = i + textStart + 1;
072         }
073         return i;
074     }
075  
076     private static int isMatch(char[] patternStamp, char[] textStamp, int[] next) {
077         int i = 0, j = 0;
078         while (j < patternStamp.length && i < textStamp.length) {
079             if (j == -1 || patternStamp[j] == textStamp[i]) {
080                 i++;
081                 j++;
082             else {
083                 j = next[j];
084             }
085         }
086  
087         if (j == patternStamp.length) {
088             return i-j;
089         else {
090             return -1;
091         }
092     }
093  
094     private static void caculateNext(char[] pattern, int[] next) {
095         next[0] = -1;
096  
097         int i = 0, j = -1;
098         while(i<pattern.length-1) {
099             if(j==-1 || pattern[i] == pattern[j]) {
100                 i++;
101                 j++;
102                 next[i] = j;
103             else {
104                 j = next[j];
105             }
106         }
107     }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章