動態規劃法
合法的括號匹配的問題之前已經講解過了,現在再看乙個括號生成的題目。
給出 n 代表生成括號的對數,請你寫出乙個函式,使其能夠生成所有可能的並且有效的括號組合。既然之前已經分析過合法的括號判斷,那麼只要把n個左括號和n個右括號全排列,然後對排列的結果去做乙個有效驗證,好了,這個問題解決了。但是仔細一分析,判斷乙個括號是否有效,複雜度o(n例如,給出 n = 3,生成結果為:
)o(n)
o(n)
,生成2n個括號字元的全排列,時間複雜度o(2
2n
)o(2^)
o(22n)
,這很難辦啊。所以全排列的方式行不通。
深度搜尋法
全排列裡面有很多左括號和右括號數目不等的,可以直接排除了,所以浪費了很多判斷。我們可以通過回溯提前把不合理的字元排除掉。但是回溯法只能是逐漸的字串變長,也就是深度優先搜尋的原理。但是我們這個時候在每一次增加括號的時候,我們保證右括號不會超過當前的左括號數目即可。還要保證最終的括號數目,左括號和右括號的數目都是n。
根據這個思想,我們可以去寫**了,我們記錄下當前左括號的數目,記錄下當前右括號的數目,如果左括號大於右括號,且左括號數目小於n,此時我們深度搜尋的路徑包括兩條,新增左括號和右括號。如果左括號數目等於n了,那麼就只有一條路徑,如果左括號數目等於右括號數目了且不等於n,此時只能新增左括號。如果兩者數目相等,且等於n,則可以返回了,已經生成了一組合法的括號字元。整個演算法就是乙個深度遍歷,可以採用遞迴來實現。
python**
class
solution
:def
generateparenthesis
(self,n)
: ans=
self.
max=n
self.backtrack(ans,"",
0,0)
return ans
defbacktrack
(self, ans, cur, left, right)
:if left==self.
max:
')'*
(self.
max- right)
)return
if(leftmax)
: self.backtrack(ans, cur +
'(', left +
1, right)
if rightself.backtrack(ans, cur +
')', left, right +
1)
可以看到,這種方式保證了左括號的數目始終多於右括號,這樣生成出來的一定是合法的括號字串。因為每次生成保證了都是合法的字首,這個複雜度就大大的減少了。
事實上,合法的括號數目,我們在卡特蘭數的應用分析了n個括號的合法種類數就是卡特蘭數列的第n項,我們大致可以根據卡特蘭數的性質,分析問題的規模。我們知道卡特蘭數的漸進上界是o(4
nn
)o\left ( \frac} \right )
o(n4n
),而每乙個合法的序列,我們是通過o(n
)o(n)
o(n)
次新增字元生成出來的。
動態規劃法
既然這個問題和卡特蘭數相關,那麼一定可以根據卡特蘭數的特點,一定可以把這個問題轉換成以前所有狀態的窮舉。說的通俗一點就是,如果我們研究問題規模為n,那麼問題規模之和為n-1的兩兩組合一定可以用得上,如果這句話理解不了可以直接跳到下一段。
我們為了降低問題規模,可以考慮在問題規模為n-1的情況上加一對括號,可是這個多出來的一對括號應該往哪加。顯然,我們可以把這個括號加在所有的合法匹配的括號之後。如果合法匹配數為0的時候,我們就把括號加在了最前面,就是()+
dpn−
1()+dp_
()+dpn
−1,再者我們可以把括號加到一對合法括號後面,也是(dp
1)+d
pn−2
(dp_1)+dp_
(dp1)
+dpn
−2依次類推,n-1個合法的括號總共可以分解出n-1種情況。每個情況分為兩部分,前面一部分是dp_i,後面一部分是dp_n-1-i,其實也就是兩部分滿足下標之和為n-1就行。
據此我們可以寫出動態規劃的遞迴式。dpi
="("
+dpj
+")"
+dpi
−j−1
,whe
re
j<
idp_i="(" + dp_j + ")"+dp_, \ where \ jdp
i="
("+d
pj+
")"+
dpi−
j−1
,whe
rej<
i。事實上,幾乎所有的卡特蘭數問題都可以寫成類似的遞推式,對所有兩兩組合為n-1的情況然後窮舉,並做出一定的修改。大家可以記住這個結論,當然也可以寫成數學表示式,我直接寫成程式的表示式即可。下面就可以根據這個表示式寫**。只需要對dpj
dp_j
dpj
和d pi
−j−1
dp_dp
i−j−
1做個全排列即可。
python**
class
solution
:# 動態規劃
defgenerateparenthesis
(self, n:
int)
-> list[
str]
: dp=[[
]for i in
range
(n+1)]
dp[0]
=['']
for i in
range(1
,n+1):
for j in
range
(i):
dp[i]
.extend(self.compent(dp[j]
,dp[i-j-1]
))return dp[n]
defcompent
(self, l, r)
: res=
for s1 in l:
for s2 in r:
'('+s1+
')'+s2 )
return res
分析時間複雜度的時候大家需要注意一下,就是雖然這個**寫出來是4個for,但是這個**的時間複雜度不是o(n
4)
o(n^4)
o(n4
),相比於上面的回溯法,其實時間複雜度的指數部分還是保持的,單是求問題規模等於n的情況,時間複雜度就已經達到了o(4
nn
)o\left ( \frac} \right )
o(n4n)。
LeetCode 有效括號生成,回溯法的應用
題目描述 給出 n 代表生成括號的對數,請你寫出乙個函式,使其能夠生成所有可能的並且有效的括號組合。題目思路 回溯法 一般排列組合的問題都需要用到遞迴演算法中的回溯思路。這道題是典型的回溯法應用的場景,只不過需要在回溯的過程中新增條件限定,不符合有效的括號組合不進行回溯即可。關於回溯法,這一篇部落格...
有效的括號
題目描述 給定乙個只包括 的字串,判斷字串是否有效。有效字串需滿足 左括號必須用相同型別的右括號閉合。左括號必須以正確的順序閉合。注意空字串可被認為是有效字串。解題思路 坦白來講這道題真的沒什麼思路,掉的坑也比較多,因為審題不認真,最後的一句話,注意空字串可被認為是有效字串。被吃掉了 最後提交的 執...
棧 有效括號
題目鏈結 題目分析 一道水題,利用棧就好了,當遇到 同理,當以上兩種情況都不滿足時,直接無效,後面的不用判斷 否則最後若棧空則有效,否則無效。class solution 配對成功出棧 else if s i top 1 st top top else if s i top 1 st top top...