1. 程式人生 > >leetcode第115題 不同的子序列 python解法(用時48ms)

leetcode第115題 不同的子序列 python解法(用時48ms)

leetcode第115題 不同的子序列 python解法(用時48ms)

該題的意思就是在一個字串中找出與給定字串相同的子序列的個數。例如在S= "rabbbit"這個字串中找到與 T="rabbit"相等的子序列的個數。

問題分析

首先,這題最好使用動態規劃(該題也被劃分動態規劃這一類)。動態規劃時通過組合子問題的解而解決整個問題的。(演算法導論第192頁)。以上面的字串為例,如果想要找出"rabbit"的子序列個數,只要在"rabbbit"中所有的’t’前面找出"rabbi"出現的次數。同樣,為了找出"rabbi"在S中出現的次數,則要找出在S中所有的’i’前面"rabb"出現的次數。以此類推。所以總的來說,就是將T先分割成不同的字串,然後找出不同字串出現的次數,看上去是將題目複雜化了,其實運算量並不大。整個程式只是將S遍歷了一遍。為了記錄T不同長度字串出現的次數,也為了後續方便查詢,先建立了一個字典dictTimes,來記錄次數,對於T = “rabbit”,此字典內容為{‘r’: 0, ‘ra’: 0, ‘rab’: 0, ‘rabb’: 0, ‘rabbi’: 0, ‘rabbit’: 0

}。好了,接下來開始遍歷字串S,比如說遍歷到S的某一位時’b’,那麼我需要檢視dictTimes中鍵為”rab“和”ra“的值,也就是在該’b’前”rab“和”ra“出現的次數,現在問題來了,怎樣建立’b’=>‘rab’和’ra’這個關係呢?
所以開始前也建立了一個滿足這樣關係的字典dictChars。這個字典的鍵是T中每一位的字元,值是T從頭到這一位的字串,具體為{‘r’: [’’], ‘a’: [‘r’], ‘b’: [‘ra’, ‘rab’], ‘i’: [‘rabb’], ‘t’: [‘rabbi’]}。這裡有兩點要注意:一,這裡值使用的是陣列,因為一個字元在T中出現的位置可能有多個,比如這裡的’b’,所以用一個數組來儲存;二,這裡第一位是‘r’,它前面是空字串。所以每當遍歷到’r’時,因為它是第一位,所以在dictTimes[r]直接加一。所以在dictTimes中加上一個鍵:"",值為1(此時dictTimes為{‘r’: 0, ‘ra’: 0, ‘rab’: 0, ‘rabb’: 0, ‘rabbi’: 0, ‘rabbit’: 0, ‘’: 1
}。這樣做的好處可以從下面的遍歷過程得知。

遍歷過程

接下來我們以S = “rabbbit”, T = “rabbit"為例來遍歷一遍。首先,第一個字元時’r’,這時檢視dictChars字典,知道它前面是空字串,然後在dictTimes中知道空字串的次數是1,所以在dictTimes中將’r’的次數加一(加dictTimes[”"],每次遇到’r’都是這樣的操作),接下來遍歷到’a’,從dictChars知道它在T中前面的字串是"r",所以在dictTimes中看"r"的值是否等於零。如果等於零,說明"r"沒有出現過,這樣的話此處的’a’就沒有用(因為湊不出有用的"ra")。但是我們的例子中dictTimes[r]等於1,所以此處的’a’有用,即將dictTimes中"ra"的值也設為1。接下來遍歷到第一個’b’,我們此時要遍歷dictChars[b]的值,看它們在前面出現的次數,這裡有一點比較關鍵,就是對於有多個值的陣列,一定要從後向前遍歷。

(關於這一點的解答,將在遍歷到第二個’b’時解釋)。在這裡由於陣列中只有"ra"出現過,所以將dictTimes[rab]=1。緊接著遍歷到第二個’b’,好的這裡來聊一聊為什麼要將陣列倒著遍歷。當我們正常遍歷時,第一個值是"ra",因為它的次數為1,所以得將dictTimes[rab]加上1,這時"rab"的次數變成2,首先這個結果是沒有錯的,但是我們得看它造成的後果。它的後果就是,遍歷到陣列第二個值"rab"時,因為它的值是2,所以dictTimes[rabb]也變成了2,這樣就錯了。因為dictTimes[rabb]應該為1。這是因為在遍歷第二個’b’時,其前出現的’rab’的次數只有1,只有當遍歷完後才變成2。而從後向前遍歷,首先處理的是"rab",這樣就不會出現上面的問題。
按照上述的方法,一步步遍歷下去,當遍歷到’t’時,我們看dictTimes[rabbi]的值(等於3),所以最後“rabbit”出現的次數就是等於3。最終的結果只要返回dictTimes[rabbit]就OK了。
這裡用的例子比較簡單,但複雜的情況也是這樣的分析,不在囉嗦。

原始碼(Python)

class Solution(object):
    def numDistinct(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: int
        """
        lengthT = len(t)
        dictTimes = {}
        dictChars = {}
        for i in range(lengthT):
            if t[i] in dictChars:
                dictChars[t[i]].append(t[:i])
            else:
                dictChars[t[i]] = [t[:i]]
        for i in range(1, lengthT+1):
            dictTimes[t[:i]] = 0
        dictTimes[''] = 1
        for char in s:
            if char in dictChars:
                for i in dictChars[char][::-1]:
                    if dictTimes[i] > 0:
                        dictTimes[i+char] += dictTimes[i]
        return dictTimes[t]

第二次寫部落格,還是緊髒,靴靴大家!!在這裡插入圖片描述