2020年4月16日 星期四

Leetcode題解 Python:四月挑戰DAY16 Valid Parenthesis String

給一字串,只有「 ()* 」組成,( 的右邊要對應一個 ),而 * 可以是 ( 或 ) 或 "",如果()都有對應則回傳True;否則False。

這題前身是只有 () 的條件,只需要計 ( 與 ) 的數量。

多了一個 * 有三種可能性,光是看到這個條件就直覺想到用DP。

這裡嘗試用計數的方法︰

若 ( 與 * 的數量加總小於 ) ,則可以中途回傳False。

接下來要考慮 **(() 與 ((**) 要如何抓出剩餘沒有配對到的 ( 。

同樣遇到 ( 而計數加一,有沒有能忽略情況一前面的 * 而遇到 ( 時才開始計數?而且情況二也能適用?

如果先 ( 後 *,* 可抵 ( 的計數,如果不夠,( 的計數最小為 0 ,當作 * 為 "" 出現。

那如果是情況二,那 ( 計數被 ) 抵消到 -1 該怎麼看?由於在一開始的條件判斷下已經不會有 ) 找不到左邊對的情況,因此可視為遇到 * 來處理。

整理一下有兩種計數:
1. ( 和 * 的加總去抵消 ) , 一旦小於 0 即 False。
2. ( 去抵消 * 和 ),最小值為 0,最後若有剩,代表 ( 找不到右邊可對。
class Solution:
    def checkValidString(self, s: str) -> bool:
        c1, c2 = 0, 0
        for c in s:
            c1 += 1 if c != ')' else -1 
            c2 += 1 if c == '(' else (-1 if c2 else 0)            
            if c1 < 0: return False
        return c2 == 0