天天看點

524. 通過删除字母比對到字典裡最長單詞524. 通過删除字母比對到字典裡最長單詞

524. 通過删除字母比對到字典裡最長單詞

第一判斷 seq in dictionary 是否是 s 的子序列;

第二傳回最長且字典序最小的字元串。

方法一:雙指針

class Solution:
    def findLongestWord(self, s: str, dictionary: List[str]) -> str:
        res = ""
        for seq in dictionary:
            i = j = 0
            while i < len(seq) and j < len(s):
                if seq[i] == s[j]:
                    i += 1
                j += 1
            if i == len(seq):
                if len(seq) > len(res) or (len(seq) == len(res) and seq < res):
                    res = seq
        return res
           

方法二:find

class Solution:
    def findLongestWord(self, s: str, dictionary: List[str]) -> str:
        res = ''
        for seq in dictionary:
            idx = -1
            for ch in seq:
                idx = s.find(ch,idx+1)               
                if idx == -1:
                    break
            else:
                if len(seq) > len(res) or (len(seq) == len(res) and seq < res):
                    res = seq       
               
        return res
           

方法三:排序優化第二個問題

将 dictionary 依據字元串長度的降序和字典序的升序進行排序,然後從前向後找到第一個符合條件的字元串直接傳回即可。

class Solution:
    def findLongestWord(self, s: str, dictionary: List[str]) -> str:
        dictionary.sort(key=lambda x: (-len(x), x))
        for seq in dictionary:
            idx = -1
            for ch in seq:
                idx = s.find(ch,idx+1)               
                if idx == -1:
                    break
            else:
                return seq
        return ""
           

方法四:動态規劃

預處理字元串 s 優化第 1 個問題。

令 f [ i ] [ j ] f[i][j] f[i][j] 表示字元串 s 中從位置 i 開始往後字元 j 第一次出現的位置。在進行狀态轉移時,如果 s 中位置 i 的字元就是 j,那麼 f [ i ] [ j ] = i f[i][j]=i f[i][j]=i,否則 j 出現在位置 i+1 開始往後,即 f [ i ] [ j ] = f [ i + 1 ] [ j ] f[i][j]=f[i+1][j] f[i][j]=f[i+1][j];是以我們要倒過來進行動态規劃,從後往前枚舉 i。

狀态轉移方程:

f [ i ] [ j ] = { i , s [ i ] = j f [ i + 1 ] [ j ] , s [ i ] ≠ j f[i][j]= \begin{cases} i, & s[i]=j \\ f[i+1][j], & s[i] \ne j \end{cases} f[i][j]={i,f[i+1][j],​s[i]=js[i]​=j​

假定下标從 0 開始,那麼 f [ i ] [ j ] f[i][j] f[i][j] 中有 0 ≤ i ≤ m − 1 0 \leq i \leq m-1 0≤i≤m−1 ,對于邊界狀态 f [ m − 1 ] [ . . ] f[m-1][..] f[m−1][..],我們置 f [ m ] [ . . ] f[m][..] f[m][..] 為 m,讓 f [ m − 1 ] [ . . ] f[m-1][..] f[m−1][..] 正常進行轉移。這樣如果 f [ i ] [ j ] = m f[i][j]=m f[i][j]=m,則表示從位置 i 開始往後不存在字元 j。

這樣,利用 f 數組,每次 O(1) 地跳轉到下一個位置,直到位置變為 m 或 t 中的每一個字元都比對成功。

class Solution:
    def findLongestWord(self, s: str, dictionary: List[str]) -> str:
        m = len(s)
        f = [[0] * 26 for _ in range(m)]
        f.append([m] * 26)

        for i in range(m - 1, -1, -1):
            for j in range(26):
                if ord(s[i]) == j + 97:
                    f[i][j] = i
                else:
                    f[i][j] = f[i + 1][j]

        res = ""
        for t in dictionary:
            match = True
            j = 0
            for i in range(len(t)):
                if f[j][ord(t[i]) - 97] == m:
                    match = False
                    break
                j = f[j][ord(t[i]) - 97] + 1
            if match:
                if len(t) > len(res) or (len(t) == len(res) and t < res):
                    res = t
        return res