Given a list of string that represent class names in CamelCaseNotation and a pattern. Write a function that returns the matching elements as a list. Example:
List:['HelloMars','HelloWorld','HelloWorldMars','HiHo']
input: 'H'->output:['HelloMars','HelloWorld','HelloWorldMars','HiHo'];
input: 'HW'->output:['HelloWorld','HelloWorldMars'];
input:'Ho'->output:[];
input:'HeWorM'->output:['HelloWorldMars'].
給出一組符合“駝峰命名規(guī)則”的字符串和一個(gè)字符模板,返回一個(gè)包含所有符合這個(gè)模板的字符串的數(shù)組。至于怎樣才算符合模板,請(qǐng)看上面的例子。
1. 詢(xún)問(wèn)
字符是不是都是大小寫(xiě)?假設(shè)是。
對(duì)空的模板如何處理?假設(shè)返回None。
輸入是不是合法的?比如模板會(huì)不會(huì)有小寫(xiě)字母開(kāi)頭的情況?假設(shè)沒(méi)有,并且輸入都是合法的。
2. 分析
規(guī)律分析
這道題沒(méi)有明顯的暴力破解,而只要摸到規(guī)律,離解題其實(shí)也不遠(yuǎn)了。
假設(shè)字符都是大小寫(xiě)字母,那么可以把一個(gè)字符串看做由大寫(xiě)字母分割的一個(gè)字符串組,例如'HelloWorldMars'可以分割成為['Hello','World','Mars']。同樣模板也可以這么分割。很明顯,模板分割后的數(shù)組長(zhǎng)度應(yīng)該小于等于字符串組的長(zhǎng)度,而且在其長(zhǎng)度范圍內(nèi),每一個(gè)元素都應(yīng)該是字符串組的子串(這里認(rèn)為相等也是子串的一種情況)。
對(duì)字符串進(jìn)行如上描述的分割,復(fù)雜度應(yīng)該是O(N),N為字符串長(zhǎng)度,因?yàn)橐闅v整個(gè)字符串。假設(shè)給出的數(shù)組里面有k個(gè)字符串,那么都進(jìn)行分割也就是k個(gè)O(Li)求和等于O(L),L為長(zhǎng)度之和。然后都和模板比較,生成模板的復(fù)雜度是O(H)假設(shè)模板長(zhǎng)度為H,每次比較的復(fù)雜度為O(min(H, Li)),總體時(shí)間復(fù)雜度是比較復(fù)雜的一個(gè)東西。
優(yōu)化
上面有一個(gè)很明顯的浪費(fèi):假設(shè)模板字符串分解后長(zhǎng)度為3,那么有必要對(duì)長(zhǎng)度為999的字符串進(jìn)行徹底分解嗎?答案是沒(méi)有必要。分解出兩個(gè)以后,就可以使用其進(jìn)行比較了。例如模板為ABC,字符串為ABCDEFG……,分解到[A,B,CDEFG……]即可。
那么,假如這個(gè)字符串分解后長(zhǎng)度還是3,但是中間夾雜很多不需要的東西怎么辦?模板為ABC,字符串大寫(xiě)字母也都是ABC,但是中間插了幾萬(wàn)個(gè)小寫(xiě)字母?對(duì)于這個(gè)問(wèn)題,我認(rèn)為是沒(méi)法優(yōu)化的,因?yàn)槟切┬?xiě)字母都得看,萬(wàn)一不看冒出一個(gè)大寫(xiě)字母來(lái),結(jié)果就錯(cuò)了。
在這一步,可以看到效率肯定提高了,但是復(fù)雜度不變,因?yàn)榭紤]的是最壞情況,還是整個(gè)字符串都得看。
然后比較。假如字符串結(jié)果的長(zhǎng)度小于模板結(jié)果長(zhǎng)度,沒(méi)有必要比較,直接fail。然后通過(guò)上面那一步,保證長(zhǎng)度都是一樣的,也就是說(shuō)是O(H)。同樣,這個(gè)也沒(méi)得優(yōu)化,必須按照模板一個(gè)個(gè)比較下去,否則萬(wàn)一里面有一個(gè)不一樣,結(jié)果是否。
因此,最后的時(shí)間復(fù)雜度為O(kH+L),空間復(fù)雜度是O(H+L)。
發(fā)散
上面的解法用了額外空間,有沒(méi)有可能不需要額外空間,直接拿出兩個(gè)字符串比較?
如果是那樣,可能要用到雙指針,一個(gè)指向模板,一個(gè)指向字符串,本質(zhì)上邏輯和分組的方法一樣,先比較完模板里面的一組,然后移動(dòng)指針到下一組開(kāi)始的地方繼續(xù)比較。因?yàn)榍闆r很多,最壞情況下時(shí)間復(fù)雜度是O(H+Li),k次也就是O(kH+L)。這種方法總體而言空間效率更好。當(dāng)然,代碼更難寫(xiě)。前面那個(gè)解法,就是按照大寫(xiě)字母分組稍微麻煩一些,之后都是很簡(jiǎn)單的編程。
不過(guò)既然有更好的解法,就寫(xiě)這個(gè)吧。
3. 代碼
class Solution:
def stringPattern(self, p, list):
if not p or not list:
return None
res = []
for s in list:
if self.isMatch(p, s):
res.append(s)
return res
def isMatch(self, p, s):
if not s:
return False
p1 = p2 = 0
while p1 < len(p) and p2 < len(s):
# compare first upper char
if p[p1] != s[p2]:
return False
else:
p1 += 1
p2 += 1
# compare rest lower char
while p1 < len(p) and p2 < len(s):
# if found next upper char, break
if 'A' <= p[p1] <= 'Z':
break
else:
if p[p1] != s[p2]:
return False
else:
p1 += 1
p2 += 1
# s skip until next upper char
while p2 < len(s) and not 'A' <= s[p2] <= 'Z':
p2 += 1
if p1 == len(p):
return True
else:
return False
4. 總結(jié)
難度medium。