每日題。今天才注意這題有follow up。

題目

輸入字串s和t,檢查s是不是t的子序列。

解法

使用雙指標,i紀錄s字串的位置,j紀錄t字串的位置。
每次將j+1,若s[i]=t[j]則表示配對成功,則也i+1。最後若i=s長度則代表整個子序列配對成功。
時間複雜度O(M+N)。

class Solution:
    def isSubsequence(self, s: str, t: str) -> bool:
        M = len(s)
        N = len(t)
        i = j = 0
        while i < M and j < N:
            if s[i] == t[j]:
                i += 1
            j += 1
        return M == i

利用python內建的疊代器解法。
建立t的疊代器it,對目標字串s中每個字元c檢查是否在it中,若全部都找到就代表是子序列。
因為內建的in語法會一直疊代查找目標直到找到為止,每次都會對it使用next()函數,所以每個字元最多使用一次。

class Solution:
    def isSubsequence(self, s: str, t: str) -> bool:
        it = iter(t)
        return all(c in it for c in s)

follow up說如果字串且s有k<=10^9個,長度M,但是t保持不變,有沒有辦法加速?使用二分搜。
維護雜湊表d,先遍歷來源字串t的字元,將index保存至d[字元]裡,例如t=’aba’,d[‘a’]=[0,2],d[‘b’]=[1]。
變數start代表字串t可以使用的範圍,初始值為0,表示整個字串都沒用過。
對s中的每個字串c,在d[c]裡面找到第一個大於等於start的值,並回傳其位置idx。若idx=d[c]大小則代表沒有可用的,直接回傳false,否則更新start為idx+1。
假設有k個字串s,每次需要O(M log N),整個時間複雜度會是O(k*M log N)。

class Solution:
    def isSubsequence(self, s: str, t: str) -> bool:
        N = len(t)
        d = defaultdict(list)
        for i in range(N):
            d[t[i]].append(i)

        start = 0
        for c in s:
            idx = bisect_left(d[c], start)
            if idx == len(d[c]):
                return False
            start = d[c][idx]+1

        return True