字串匹配問題,給定一串字串,按照指定規則對其進行匹配,並將匹配的結果儲存至output陣列中,多個匹配項用空格間隔,最後乙個不需要空格。
要求:1. 匹配規則中包含萬用字元?和*,其中?表示匹配任意乙個字元,*表示匹配任意多個(>=0)字元。
2. 匹配規則要求匹配最大的字元子串,例如a*d,匹配abbdd而非abbd,即最大匹配子串。
3. 匹配後的輸入串不再進行匹配,從當前匹配後的字串重新匹配其他字串。
我們先考慮rule是否匹配input某乙個字首的情況的情況
設狀態dp[i][j]為rule[i]與input[j]是否匹配(true或false)
分別考慮rule[i]==?,*以及普通字元的情況
rule[i]='*'
時:1. dp[i][j-1]==true能推出di[i][j]==true但是dp[i][j-1]==false不能推出dp[i][j]==false(考慮rule[0...i]=abc*和input[0...j-1]=ab且input[j]=c。所以不能用dp[i][j-1]
2. 應該用dp[i-1][j]和dp[i-1][j-1]。其實是一樣的,因為dp[i-1][k]=true即可推出dp[i][j]=true(其中0<=k<=j)。否則就是false。即dp[i][j]與dp[i-1][k]的或等價。
rule[i]='?'
時:1. dp[i][j-1]和dp[i-1][j]都不能推斷出dp[i][j]。比如dp[i][j-1]=ture時,如果rule[0…i]都是普通字元,則明顯dp[i][j]=false。但是如果rule[0…i]=*時,則明顯dp[i][j]也是true。同理dp[i-1][j]也不能(分別考慮rule[0…i-1]是普通字串和是*的情況)
2. dp[i-1][j-1]與dp[i][j]是無條件等價的,可以分別考慮dp[i-1][j-1]=true或false的情況。
rule[i]
為普通字元時:
1. 同rule[i]==』?』一樣,無法通過dp[i][j-1]和dp[i-1][j]推斷出dp[i][j]
2. (dp[i-1][j-1]&&rule[i]==input[j])與dp[i][j]等價。
設rule,input都從1開始:
初始化:
dp[0][1….j_len]=flase
dp[1…i_len][0]=false
dp[0][0]=true.
動態規劃遞迴式為:
1. rule[i]==』*』:dp[i][j]=(dp[i-1][k]的或,k=0…j)
2. rule[i]!=』*』:dp[i][j]=(dp[i-1][j-1]&&(rule[i]==input[j]||rule[i]=』?』))
從該題得到的思考:
動態規劃的遞迴式需要是充分必要條件:
充分:
即當滿足遞迴式時,一定能給出正確的結果。在該題中,即當rule=』?』且dp[i-1][j-1]=ture時dp[i][j]一定是ture。
必要性:
所有結果都能通過該遞迴式得到,不能有遺漏。即完備性。
動態規劃的完備性其實很好證明,比如在本題中,只要考慮rule[i]的3種可能取值和將dp[i][j]表填滿就行了。即rule=』?』時,雖然dp[i][j-1]和dp[i-1][j]不能用,但是可以通過dp[i-1][j-1]就可以得出結果,加上初始化的值,就可以得出整個dp表的值。
以上是快速判斷rule是否與input匹配的演算法。但是題目其實是要知道rule是否與input的某一子段匹配,乙個方法就是遍歷以input[0]到input[len]開頭的所有子串。即在外面再加一層迴圈。複雜度是(rule_len)*(input_len)^2。
但是其實改一下狀態設定就可以直接用動態規劃解決。
設狀態dp[i][j]為rule[0…i]匹配以input[j]結尾的input字串的最大長度
分別考慮rule[i]==?,*以及普通字元的情況如上
rule[i]='*'
時:
若dp[i-1][k]!=-1,則dp[i-1][k]+j-k就是dp[i][j]
當然,得從眾多的k中選乙個最大的,即dp[i][j]=max
rule[i]='?'
時:rule[i]
為普通字元時:
rule[i]必須與input[j]對應上,而且要想將rule[0…i]都匹配上,dp[i-1][j-1]就不能等於-1,即必須匹配。
即dp[i-1][j-1]!=1且rule[i]與input[j]匹配(rule[i]==input[j]||rule[i]=』?』)
設rule,input都從1開始:
初始化:
dp[0][1….j_len]=0
dp[1…i_len][0]=-1
dp[0][0]=0
動態規劃遞迴式為:
3. rule[i]==』*』:dp[i][j]=max(dp[i-1][k]+j-k)0<=k<=j且dp[i-1][k]!=-1)
4. rule[i]!=』*』:dp[i][j]=(dp[i-1][j-1]!=-1&&(rule[i]==input[j]||rule[i]=』?』))?dp[i-1][j-1]+1:-1;
其中初始化的dp[0][1….j_len]=0很重要。例如rule=」n」,input=」nsn」。當n匹配到nsn的第二個n時,就是求dp[1][3]時,要看dp[0][2],如果dp[0][2]=-1,則意味著rule中n字母之前的就已經不匹配,所以該n也不能匹配。但是很明顯,n之前沒有字母需要匹配,即要把dp[0][0…len]這種特殊情況摘出來。即不需要考慮之前是否匹配(因為不需要),從新開始匹配。
帶萬用字元的字串匹配 動態規劃
描述 萬用字元是一類鍵盤字元,當我們不知道真正字元或者不想鍵入完整名字時,常常使用萬用字元代替乙個或多個真正字元。萬用字元有問號 和星號 等,其中,可以代替乙個字元,而 可以代替零個或多個字元。你的任務是,給出乙個帶有萬用字元的字串和乙個不帶萬用字元的字串,判斷他們是否能夠匹配。例如,1?456 可...
帶萬用字元的字串匹配
05 帶萬用字元的字串匹配 描述萬用字元是一類鍵盤字元,當我們不知道真正字元或者不想鍵入完整名字時,常常使用萬用字元代替乙個或多個真正字元。萬用字元有問號 和星號 等,其中,可以代替乙個字元,而 可以代替零個或多個字元。你的任務是,給出乙個帶有萬用字元的字串和乙個不帶萬用字元的字串,判斷他們是否能夠...
OpenJudge 帶萬用字元的字串匹配
萬用字元是一類鍵盤字元,當我們不知道真正字元或者不想鍵入完整名字時,常常使用萬用字元代替乙個或多個真正字元。萬用字元有問號 和星號 等,其中,可以代替乙個字元,而 可以代替零個或多個字元。你的任務是,給出乙個帶有萬用字元的字串和乙個不帶萬用字元的字串,判斷他們是否能夠匹配。例如,1?456 可以匹配...