算法(8):动态规划

这是我最想写的一篇文章之一了~ 因为这玩意真难......



例题1:求目标和(Target Sum,在算法(7)堆栈习题3中出现过,这里给出另一种解法)。给定一个数组以及一个目标数S,你可以给数组中每个数分配 运算符‘+’ 或 ‘-’ 其中之一,使得数组之和为目标S。输出共有多少种分配方式。
输入: nums is [1, 1, 1, 1, 1], S is 3.
输出: 5
解释:
-1+1+1+1+1 = 3
+1-1+1+1+1 = 3
+1+1-1+1+1 = 3
+1+1+1-1+1 = 3
+1+1+1+1-1 = 3
代码解析:使用备忘录法。

class Solution:
    def findTargetSumWays(self, nums: list, S: int, ) -> int:
        if nums == []:
            return 0
        dic = {nums[0]: 1, -nums[0]: 1} if nums[0] != 0 else {0: 2}
        for i in range(1, len(nums)):
            tdic = {}
            for d in dic:
                tdic[d + nums[i]] = tdic.get(d + nums[i], 0) + dic.get(d, 0)
                tdic[d - nums[i]] = tdic.get(d - nums[i], 0) + dic.get(d, 0)
            dic = tdic
        return dic.get(S, 0)

if __name__ == '__main__':
    nums = [1, 1, 1, 1, 1]
    S = 3.
    solution = Solution()
    steps = solution.findTargetSumWays(nums,S)
    print(steps)

例题2:最大子数组(Maximum Subarray),给出一个数组,找到一个连续的子数组(至少一个元素),该子数组有最大和,返回该最大和。
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: [4,-1,2,1] 有最大和,为6.

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        curSum = maxSum = A[0]
        for num in A[1:]:
            # 这句代码可以理解成:curSum = num if curSum < 0 else num + curSum
            curSum = max(num, curSum + num)
            maxSum = max(maxSum, curSum)

        return maxSum

例题3:解码方法(Decode Ways)。
给A到Z编码如下:

'A' -> 1
'B' -> 2
...
'Z' -> 26

现如今给一个非空字符串,里面由数字0到9组成,问有多少种解码方式?
例题:
输入: "226"
输出: 3
解释: "BZ" (2 26), "VF" (22 6), or "BBF" (2 2 6).

注意事项:我当时做这道题的时候忽略了0这个特殊的存在,因为0不对应任何一个字母。比如一个字符串中出现了‘00’,那么该字符串输出就一定是0......下面给出了两种代码,供参考。

class Solution:
    def numDecodings(self, s: str) -> int:
        # v, w, p = 0, int(s>''), ''
        # for d in s:
        #     v, w, p = w, (d>'0')*w + (9<int(p+d)<27)*v, d
        # return w
        # w tells the number of ways
        # v tells the previous number of ways
        # d is the current digit
        # p is the previous digit
    
    
        #dp[i] = dp[i-1] if s[i] != "0"
        #       +dp[i-2] if "09" < s[i-1:i+1] < "27"
        if s == "": return 0
        dp = [0 for x in range(len(s)+1)]
        dp[0] = 1
        for i in range(1, len(s)+1):
            if s[i-1] != "0":
                dp[i] += dp[i-1]
            if i != 1 and "09" < s[i-2:i] < "27":  #"01"ways = 0
                dp[i] += dp[i-2]
        return dp[len(s)]

例题4:丑数,丑数为只能被2,3,5整除的数(1定义为第一个丑数),输入一个整数n,输出第n个丑数。
输入:10
输出:12(前十个丑数序列:1, 2, 3, 4, 5, 6, 8, 9, 10, 12)
代码解释:用了三指针技术,对每个丑数再乘以2,3或5就是新的丑数,但是为了使得输出有序,需要三个指针来记录位置。

class Solution:
    def nthUglyNumber(self, n: int) -> int:
        ugly = [1]
        i2, i3, i5 = 0, 0, 0
        while n > 1:
            u2, u3, u5 = 2 * ugly[i2], 3 * ugly[i3], 5 * ugly[i5]
            umin = min((u2, u3, u5))
            if umin == u2:
                i2 += 1
            if umin == u3:
                i3 += 1
            if umin == u5:
                i5 += 1
            ugly.append(umin)
            n -= 1
        return ugly[-1]

例题5:最长递增子序列(Longest Increasing Subsequence),给出一个未排序的整型数组,返回其最长递增子序列长度。
输入: [10,9,2,5,3,7,101,18]
输出: 4 (其中最长递增子序列为[2,3,7,101])
代码解释:(下文sub 数组里存放的元素可能不是实际的递增子序列,但其长度是准确的)

leetcode(Longest Increasing Subsequence)

  1. initial sub = [ ].
  2. traversing the nums:
    a) if val > sub's all elements, then subsequence length increased by 1, sub.append(val);
    b) if sub[i-1] < val < sub[i], then we find a smaller value, update sub[i] = val. Some of the elements stored in the sub[ ] are known subsequences, and the other part is elements of other possible new subsequences. However, the length of the known subsequences is unchanged.
  3. return the sub[ ]'s length.

Here is the solution's track, as we have nums = [8, 2, 5, 1, 6, 7, 9, 3],when we traversing the nums:

i = 0, sub = [8]
i = 1, sub = [2]
i = 2, sub = [2, 5]
i = 3, sub = [1, 5], # element has been changed, but the sub's length has not changed.
i = 4, sub = [1, 5, 6]
i = 5, sub = [1, 5, 6, 7]
i = 6, sub = [1, 5, 6, 7, 9]
i = 7, sub = [1, 3, 6, 7, 9] #done! Although the elements are not correct, but the length is correct.

Because of sub[ ] is incremental, we can use a binary search to find the correct insertion position.

class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:
        # O(nlogn) solution with binary search
        def binarySearch(sub, val):
            lo, hi = 0, len(sub)-1
            while(lo <= hi):
                mid = lo + (hi - lo)//2
                if sub[mid] < val:
                    lo = mid + 1
                elif val < sub[mid]:
                    hi = mid - 1
                else:
                    return mid
            return lo

        sub = []
        for val in nums:
            pos = binarySearch(sub, val)
            if pos == len(sub):
                sub.append(val)
            else:
                sub[pos] = val
        return len(sub)

我先把常见问题写在这,省的日后忘了:

  1. 求一个字符串的最长回文子串

LeetCode 上的五种解法
马拉车算法


  1. 两个字符串的最长子序列

最长子序列

1
2

  1. 两个字符串的最长公共子串

最长公共子串

公式比最长子序列更简单,如下所示:
c[i][j]=1 +c[i-1][j-1] \ \ \ \ \ \ \ \ \ if \ \ x_i = y_i c[i][j] = 0 \ \ \ \ \ \ \ \ \ if \ \ x_i != y_i

公共字串


  1. 背包问题

背包九讲PDF下载链接:http://vdisk.weibo.com/s/zmfTPG2vgAcNV


  1. 股票买卖问题

5种股票买卖问题
上面的第五道题,买卖需要冷却的问题,可参考下面链接,讲的更详细,代码也更精致:Best Time to Buy and Sell Stock with Cooldown


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342