下面是我自己的解答
#include "stdafx.h"
#include #include #define max_len 128
bool match(char *s, char *p)
if(*p ==
'\0'
) return
false
; memset(dp, false
, sizeof
dp);
dp[0][0] = true
; int
len_s = strlen(s), len_p = strlen(p);
for(
intj = 1; j <= len_p; j++) else
if(dp[i][j-1])
} }
} return
dp[len_s][len_p];
} };
解法二(遞迴解法):
解法一不能過大資料的原因在於兩層for迴圈其實執行了多餘的匹配過程,其實對於這種匹配來說如果*s和*p相等的話我們可以直接把指標往後移動,從而把資料規模縮小。這種做法的難點同樣在對*號的處理上,因為*號可以匹配多個字元,所以在遞迴解法中需要回溯。
因為遞迴和回溯的代價都太高,所以該解法也只能過小資料,不能過大資料。
具體**實現如下:
[cpp]view plain
copy
//遞迴解法
class
solution
if(*p ==
'\0'
) return
false
; while
(*s && *p)
} else
return
false
; } else
s++, p++;
} return
ismatch(s, p);
} };
解法三(非遞迴解法)
解法三其實是對解法二的改進,即把演算法二改為非遞迴,但是解法二中的遞迴並不是尾遞迴,如果要改為非遞迴的話為了回溯就需要自己構造堆疊,幸運的是,在這裡我們並不需要構造堆疊,而只需要通過兩個變數pre_s和pre_p來儲存上一次它們開始比較的位置,然後在回溯的時候我們從上一次比較的位置的後乙個位置開始比較。
那麼這麼做的原理何在呢?首先,如果p串中只有乙個*號,那麼這麼做無疑是正確的,那麼對於有多個*號的情況,我們來看乙個例子,s="accbcbccx", p="a*b*d",按解法二第乙個*號其實是匹配了cc,即accb和a*b匹配了,剩下的cbccx交給*d去匹配,試想如果cbccx和*d匹配失敗了,我們回溯到上乙個*號去匹配是否能夠成功呢?還是不能!因為*是可以匹配任意長度的,就算回到上一次的*號位置,讓accbcb去和a*b匹配了,剩下的ccx和*d還是不能匹配,因為其實第二個*既可以匹配ccx也可以匹配cbccx,即是說後面的*號可以代替前面的*號的作用。總結一下,我們得出結論,在遇到*好不匹配時,我們直接回到上一次開始比較的位置的後乙個位置開始比較就可以了,如果能匹配必然能找到匹配,如果不能匹配,那麼再回溯也是沒用的。而這也是解法三比解法二除了遞迴開銷以外更節省時間的地方。
該解法可以過大資料。
具體**實現如下:
[cpp]view plain
copy
//非遞迴解法
class
solution else
if(has_star) else
return
false
; } else
s++, p++;
} while
(*p ==
'*') p++;
return
*p ==
'\0'
; }
};
第一題的解法到此結束。
下面來看第二題的解法:
首先第二題和第一題還是有些類似的,但是區別在於這次是*號之前的字元可以出現多次,比如說a*b可以和ab也可以和aab匹配,甚至也可以和b匹配,因為a可以出現0次。
那麼該題的解法就和第一題類似了,在比較的時候首先判斷*(p+1)是否是*號,如果是就需要遞迴回溯判斷,如果不是就挨個比較就行了。
具體**實現如下:
[cpp]view plain
copy
class
solution
return
ismatch(s, p+2);
//如果不等,那麼只有跳過*p了
} else
} };
可能在leetcode上的測試資料比較弱,該遞迴演算法是可以過大資料的。
那麼這個題目可不可以像第一題那樣改為非遞迴而又只需儲存上乙個開始匹配的位置呢?答案是不能!我們來看個例子s="cbcbc", p=".*b*c",首先按照上述遞迴演算法c和.*匹配了,b和b*匹配了,剩下cbc去和c匹配,顯然不匹配,如果回到上一次的*號處,讓cbc繼續去和b*c匹配,肯定也是不能匹配的,如果只儲存了上乙個開始匹配的位置,那麼該演算法就會判斷為不能匹配了,可實際上s和p是可以匹配的,讓cbc去和.*匹配,剩下的bc和b*c匹配就可以了。因此這種設想是行不通的。分析一下,上一題中這種做法能行得通,而這次行不通的原因在於,上一題中的*可以匹配任何字串,而這一題中的b*其實只能匹配以b開頭的字串或者空串,這正是區別之所在。
所以如果這次還要改為非遞迴的話,就需要自己構造堆疊了!(**沒實現)
-----over------
參考:
動態規劃演算法的理解
動態規劃演算法主要的核心思想是 狀態和狀態轉移方程。怎麼理解這個問題呢?先拿到了乙個數字三角形的程式,閱讀了它的動態規劃的 但是看不明白!不明白在什麼地方呢?在具體的執行過程各個變數的變化方向。比如兩層for迴圈,i為逆序,j為次序。那麼這種執行次序就沒有辦法想象了。那就先不管上面的了,先看dag上...
LCS的動態規劃演算法
輸入 兩個字串 輸出 最長公共子串行 演算法思想 動態規劃 include include using namespace std string x,y 輸入串 int c 100 100 維護lcs length的陣列 int b 100 100 用於構造乙個最優解 int lcs len str...
動態規劃演算法的例子
標籤 空格分隔 演算法知識文件 動態規劃 問題 求圖中一點到圖中其他點的最短路徑 輸入 起點集合 終點集合 中間結點集合,邊的集合 e e 對於任意邊e e role presentation style position relative e e e e有長度 輸出 一條從起點到終點的最短路徑 乙...