递归+HashMap套路(可以对付可降解问题)

115. 不同的子序列

给定一个字符串 S 和一个字符串 T,计算在 S 的子序列中 T 出现的个数。

一个字符串的一个子序列是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,"ACE" 是 "ABCDE" 的一个子序列,而 "AEC" 不是)

题目数据保证答案符合 32 位带符号整数范围。

示例 1:

输入:S = "rabbbit", T = "rabbit"

输出:3

解释:

如下图所示, 有 3 种可以从 S 中得到 "rabbit" 的方案。

rabbbitrabbbitrabbbit 就是三个bbb,中不取哪个b,有三种情况。

个人考虑是用递归:

匹配了一个,那么就是S,T从这开始后子串再做比较(递归),当然因为不是只找出一个解,而是求一共有多少,所以这个不去匹配,从S的下一个位置开始,继续找匹配的代码也要写。

然后就是递归一旦开多条分支,就会组合爆炸(实际一条分支是不会的,问题是一条分支,开递归干嘛,除非是教程里的阶乘,这个本来就不需要递归)。为了不重复计算,采用了S剩下几个,T剩下几个字母,然后有多少解,除了第一次,算完后,这个放在map中保存(S剩余字母数*1000+T剩余字母数,作为key,值是多少解),以后遇到同样情况,直接就用map里的值,这样大大提升效率,因为他里面测试的S是有几百个字符的,组合可以到几千万种,用了map,实际就记录了200多个,速度也快多了。不过即便如此,个人的程序执行速度是仅仅击败了5.59%的用户(500ms),从CSDN里找了一个高手的程序,放在LeetCode测试,果然他的只用了20多ms。哦,太惊人了。

当然个人并没有学习高手的逻辑,估计是非常贴合该问题的。作为一般程序员,完全贴合问题的数学模型是有难度的,用递归+map(防止组合爆炸),可以解决许多问题(可降解问题),一般x(N)转成x(N-1)或x(N-m)问题,总是朝着解决的方向前进,而只要有个递归式,以及收尾(到某一步不再递归),另外进入函数时判断map中是否存在,退出函数时,结果记入map。就这样一套,应该能解决一大类问题,包括动态规划。。。

class Solution(object):
    def numDistinct(self, s, t):
        map = {}
        return self.num_dist(s,t,map)
    def num_dist(self,s,t,map):
        c = 0
        for i in range(len(s)-len(t)+1):
            if s[i] == t[0]:
                if len(t) == 1:
                    c += 1
                else:
                    v = map.get((len(s)-i-1)*1000+len(t)-1)
                    c = c+v if v != None else c+ self.num_dist(s[i+1:],t[1:],map)
        map.update({len(s)*1000+len(t):c})
        return c

 又比如:LeetCode410

410. 分割数组的最大值

给定一个非负整数数组和一个整数 m,你需要将这个数组分成 个非空的连续子数组。设计一个算法使得这 个子数组各自和的最大值最小。

注意:
数组长度 满足以下条件:

  • 1 ≤ n ≤ 1000
  • 1 ≤ m ≤ min(50, n)

示例:

输入:
nums = [7,2,5,10,8]
m = 2

输出:
18

解释:
一共有四种方法将nums分割为2个子数组。
其中最好的方式是将其分为[7,2,5] 和 [10,8],
因为此时这两个子数组各自的和的最大值为18,在所有情况中最小。

思路:
其实数组是没有排序的,一开始以为是排序数组,那么就从末段开始查找,很少几个数就能超过平均值,
找到后,比如上边例子:8没有超过一半,再加上10就超过一半了,这时:
A1[7,2]分一组,A2[5,10,8] 这里面取大
B1[7,2,5]分一组,B2[10,8] 这里面取大
C1[7,2,510]分一组,C2[8] 这里面取大
然后这三行中取小,当然这里m=2,实际m可以等于50,这个时候,前面的部分调用split_x(nums,i+1,m-1,mapx)
就是前面部分再分成49组,这样的递归,为了防止组合爆发,加个map就行了,另外也采用剪枝
继续用上边例子:
对于某一搜索的结果:min(max(A1,A2),max(B1,B2),max(C1,C2))
A1<=B1<=C1,A2>B2>C2
当B2>C1的时候,实际B1就不用求了,A1更不用谈了
时间也从原来不知道多少秒(不加map太可怕了)变成了15ms(一共有27个测试)
if True:
    class Solution410(object):
        def splitArray(self, nums, m):
            mapx = {}
            v = self.split_x(nums,len(nums),m,mapx)
            print(len(mapx))
            return v
        def split_x(self,nums,last_ptr,m,mapx):
            v = mapx.get(last_ptr*100+m)
            if v != None:return v
            
            if m == 1:
                v = sum(nums[:last_ptr])
            else:
                sum_last = 0
                sum_share = sum(nums[:last_ptr])//m
                for i in range(last_ptr-1,-1,-1):
                    sum_last += nums[i]
                    if sum_last > sum_share:
                        v2 = self.split_x(nums,i+1,m-1,mapx)
                        if sum_last > v2:
                            v = v2
                        else:
                            v1 = self.split_x(nums,i,m-1,mapx)
                            sum_left = sum_last+nums[i-1]
                            v = min(max(v1,sum_last),v2) if sum_left > v2 else min(max(self.split_x(nums,i-1,m-1,mapx),sum_left),max(v1,sum_last),v2)
                        break
            mapx.update({last_ptr*100+m:v})
            return v

    print(Solution410().splitArray([7,2,5,10,8],2))
    print(Solution410().splitArray([499,498,497,496,495,494,493,492,491,490,489,488,487,486,485,484,483,482,481,480,479,478,477,476,475,474,473,472,471,470,469,468,467,466,465,464,463,462,461,460,459,458,457,456,455,454,453,452,451,450,449,448,447,446,445,444,443,442,441,440,439,438,437,436,435,434,433,432,431,430,429,428,427,426,425,424,423,422,421,420,419,418,417,416,415,414,413,412,411,410,409,408,407,406,405,404,403,402,401,400,399,398,397,396,395,394,393,392,391,390,389,388,387,386,385,384,383,382,381,380,379,378,377,376,375,374,373,372,371,370,369,368,367,366,365,364,363,362,361,360,359,358,357,356,355,354,353,352,351,350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271,270,269,268,267,266,265,264,263,262,261,260,259,258,257,256,255,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,239,238,237,236,235,234,233,232,231,230,229,228,227,226,225,224,223,222,221,220,219,218,217,216,215,214,213,212,211,210,209,208,207,206,205,204,203,202,201,200,199,198,197,196,195,194,193,192,191,190,189,188,187,186,185,184,183,182,181,180,179,178,177,176,175,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,159,158,157,156,155,154,153,152,151,150,149,148,147,146,145,144,143,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128,127,126,125,124,123,122,121,120,119,118,117,116,115,114,113,112,111,110,109,108,107,106,105,104,103,102,101,100,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0],50))
原文地址:https://www.cnblogs.com/nocomment/p/13274241.html