每日題。之前寫過兩次,但是完全看不懂之前在寫什麼鬼,整個思路都不一樣了。

題目

輸入一個words陣列,其中每個單字都由小寫英文字母組成。
若我們可以在wordA的某個位置插入新字元,使之成為wordB,則稱wordA是wordB的前身
例如,”abc”是”abac”的前身,而”cba”不是”bcad”的前身。

單字鍊指的是一個單字序列[word1, word2, …, wordk],且k>=1,每個word皆為其後方word的前身
回傳從words中可以組成的最長單字鍊長度。

解法

對於某個單字w長度為x,那麼他可以作為(x+1)*26種單字的前身,複雜度是稍微高了一些。
提示說:與其在w上插入新的字元,不妨試著刪掉某個字元。這樣複雜度就是剩下O(x)了。

那麼我們的問題簡化成words中所有單字中,可以往前找到多少前身,答案就是找到的前身數+1。
定義dp(w)為:單字w可以組成的最大單字鍊長度。
轉移方程式:dp(w) = 1 + max(dp(pred) FOR ALL pred in words)
base cases:當w長度為1時,不會再有前身了,直接回傳1。

但是最長的單字鍊不一定是從最長的word開始而成,所以要從所有單字出發,並找出最佳結果。

class Solution:
    def longestStrChain(self, words: List[str]) -> int:
        wd=set(words)
        
        @cache
        def dp(w):
            if len(w)==1:
                return 1
            best=0
            for i in range(len(w)):
                pred=w[:i]+w[i+1:]
                if pred in wd:
                    best=max(best,dp(pred))
            return best+1
   
        return max(dp(w) for w in words)