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]

第二次写博客,还是紧脏,靴靴大家!!在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Whyalwaysxu/article/details/85079685