2020年4月25日 星期六

Leetcode題解 Python:Restore The Array

給一由數字組成的字串,可以在任意位置上切割,但每個切割出來的數字要在[1,k] 之間,而且分割出來的數字不能有前導零的出現,要回傳有幾種可能。

(可能組合數很多,回傳結果對 10^9+7 的取餘)

這題明顯是dp的題目,因為要找出所有組合數,而且答案可能超級大。

如果使用遞迴函數,因為這題的 s.Length 可達 10^5,因此可能會超出最大遞迴深度而報錯。

先繼續講如何設計。

從位置[0]開始,如果左方的數字在[1,k] 之間,可以選擇在這裡切,或是住下一位切。因為要記錄上次的切割位置,所以得設一參數接收。
memo[pos][slicePos]

如果切,往深 dfs(pos+1, pos+1);不切,dfs(pos+1, slicePos)。

要是下一位是 "0" 或是左方數字 < 1 ,那就只能不切,因為在這遞迴函數只取符合規則的方法數。

接著來思考中止條件。

如果 pos == s.length,檢查左方數字是否在範圍內,決定回傳 1 或 0 。

如果 int(s[slicePos:pos+1]) > k ,超出範圍,即回傳 0 。


python
class Solution:
    def numberOfArrays(self, s: str, k: int) -> int:
        n = len(s)
        
        @lru_cache(None)
        def nextPos(i, j):            
            if i == n:
                if j != n and int(s[j:n]) >= 1 and int(s[j:n]) <= k: return 1
                return 0   
            while i < n-1 and s[i+1] == "0": 
                i += 1                                
            lnum = int(s[j:i+1])
            if lnum > k: return 0   
            return (nextPos(i+1, j)+nextPos(i+1, i+1)) % (10**9+7)
        
        # 由於可能超出最大深度,所以先執行一半
        nextPos(len(s)//2, len(s)//2)
        
        return nextPos(0, 0)