2. 如果不想用递归,可以考虑另外一种思路是
对于t,可以看成被一些*串(连续的*组成的子串)划分成了一组跟s一样纯由字母组成的子串。
这样问题就转化成了在s中寻找一个子串序列。
- 开始时还像普通的串匹配一样,移动s和t,直到t遇到第一个*
- 然后t后面的部分假设被*串划分成如下一组字符字串:t1, t2, t3
- 那么问题变成了从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, int textEnd, 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 |
}
|