07-03:动态规划review1

1、最大连续子数组和

    关键核心是累加和的正负:



2、零钱组合

1)最少硬币数

总钱数:总硬币数:动态规划迭代:

外部总硬币数:

内部总钱数:

自底向上迭代:

核心代码如下:
dp = [float('inf')] * (amount + 1)

        dp[0] = 0

        for coin in coins:

            for j in range(coin,amount+1):

                  dp[j] = min(dp[j], dp[j - coin] + 1)

        return dp[amount] if dp[amount] != float('inf') else -1

零钱组合1

2)满足钱数的多少种组合数

外部总硬币数:

内部总钱数:

自底向上累加:

核心思路:

对于面额为coin 的硬币,当 coin≤i≤amount 时,如果存在一种硬币组合的金额之和等于 i −coin,则在该硬币组合中增加一个面额为 coin 的硬币,即可得到一种金额之和等于 i的硬币组合。因此需要遍历 coins,对于其中的每一种面额的硬币,更新数组 dp 中的每个大于或等于该面额的元素的值。

核心代码如下:

n=len(coins)

        if amount==0 or n==0:

            return 1


        dp=[0]*(amount+1)

        dp[0]=1

        for coin in coins:

            for j in range(coin,amount+1):

                dp[j]=dp[j]+dp[j-coin]


        return dp[amount]

3)组合总数

leetcode377

给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。

https://leetcode-cn.com/problems/combination-sum-iv/

dp=[0]*(target + 1)

        dp[0] = 1

        for  i in range(1,target+1):

            for  num  in nums:

                  if num <= i:

                    dp[i] += dp[i - num]

        return dp[target]

3、01背包

总体积:总物品数:动态规划迭代:体积V

核心问题:

自顶向下不断递归迭代

核心代码:

if V<=0 or n<=0:

            return 0

        dp=[0 for i in range(V+1)]


        for i in range(n):

            vi=vw[i][0]

            wi=vw[i][1]

            for j in range(V,vi-1,-1):

                dp[j]=max(dp[j-vi]+wi,dp[j])


        return dp[V]

牛客网01背包问题:
https://www.nowcoder.com/practice/2820ea076d144b30806e72de5e5d4bbf?tpId=196&&tqId=37561&rp=1&ru=/activity/oj&qru=/ta/job-code-total/question-ranking


1)完全平方数

核心代码如下:

k=int(sqrt(n))

        dp=[float('inf')]*(n+1)

        dp[0]=0

        dp[1]=1

        for i in range(1,k+1):

            tmp=i*i

            for j in range(tmp,n+1):

                dp[j]=min(dp[j],dp[j-tmp]+1)


        return dp[n]


2)掷骰子的N种方法

leetcode1155

投掷骰子的方法数:d个骰子,每个有f个面(点数为1,2,...f),求骰子点数和为target的方法

分组0/1背包的组合问题:dp[i][j]表示投掷i个骰子点数和为j的方法数;三层循环:最外层为背包d,然后先遍历target后遍历点数f

应用二维拓展的转移方程3:dp[i][j]+=dp[i-1][j-f];

链接:https://leetcode-cn.com/problems/coin-change/solution/yi-pian-wen-zhang-chi-tou-bei-bao-wen-ti-sq9n/


3)最长递增子序列 leetcode300

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

1、贪心+二分查找

贪心:保持数组递增

二分查找:查找不满足大于数组最大值的位置,第一个小于原数组中元素

时间复杂度:o(nlogn)

空间复杂度:o(n)

核心代码:

n=len(nums)

        l=[]

        length=0

        if n<=1:

            return len(nums)

        l.append(nums[0])

        for i in range(1,n):

            if  nums[i]>l[-1]:

                      l.append(nums[i])

            else:

                #在数组中二分查找,找到第一个比 nums[i] 小的数,并更新 d[k + 1] = nums[i]。

                k=len(l)

                left=0

                right=k-1

                while left<=right:

                    mid=(left+right)//2

                    if l[mid]<nums[i]:

                        left=mid+1

                    else:

                        right=mid-1

                l[left]=nums[i]


        return len(l)

调用函数代码简单:

import bisect

class Solution:

    def lengthOfLIS(self, nums: List[int]) -> int:


        n=len(nums)

        ls=[]

        if n<=1:

            return len(nums)

        dp=[1 for i in range(n)]

        ls.append(nums[0])

        for i in range(n):

                if nums[i]>ls[-1]:

                  ls.append(nums[i])

                else:

                    tmp=bisect.bisect_left(ls,nums[i])

                    ls[tmp]=nums[i]


        return len(ls)

2、动态规划

包含当前数组元素的上升子序列最大值,状态转移:dp[i]=max(dp[i],dp[i-j]+1),nums[i]>nums[j]

核心代码:

n=len(nums)

        l=[]

        if n<=1:

            return len(nums)

        dp=[1 for i in range(n)]

        for i in range(n):

            for j in range(i):

                if nums[i]>nums[j]:

                  dp[i]=max(dp[i],dp[j]+1)


        return max(dp)

https://leetcode-cn.com/problems/longest-increasing-subsequence/

3、字典序最长上升子序列

一共需要两个辅助数组和一个辅助变量:

dp数组:用来存储位置i对应的最长子序列的长度

end数组:用来存储长度为i的子序列的最后一个元素的最小值

len:用来记录当前找到的最长子序列的长度

最后产生字典序最小的:

核心代码如下:

import bisect

#bisect.bisect_left(ls,arr[i]),返回第一个小于arr[i]的索引

def LIS(self , arr ):

        # write code here

        if not arr:

            return 0

        n=len(arr)

        dp = [1 for i in range(n)]

        ls=[arr[0]]

        res=[]

        for i in range(1,n):

                  if arr[i] > ls[-1]:

                        ls.append(arr[i])

                        dp[i]=len(ls)

                  else:

                        tmp=bisect.bisect_left(ls,arr[i])

                        ls[tmp]=arr[i]

                        dp[i]=tmp+1

        lls=len(ls)

        res=[0]*lls

        for i in range(n-1,-1,-1):

            if dp[i]==lls:

                res[lls-1]=arr[i]

                lls=lls-1

        return res

https://www.nowcoder.com/practice/9cf027bf54714ad889d4f30ff0ae5481?tpId=117&&tqId=37796&rp=1&ru=/activity/oj&qru=/ta/job-code-high/question-ranking


4)最长回文串长度

动态规划节最长回文子串长度:

核心代码如下:

dp=[[False]*n for i in range(n)]

            smax=0

            for d in range(n):

                for i in range(n-d):

                    j=i+d

                    if A[i]==A[j]:

                        if d==0 or d==1 or d==2:

                            dp[i][j]=True

                        else:

                            dp[i][j]=dp[i+1][j-1]

                        if dp[i][j]:

                            smax=max(smax,d+1)

            return  smax

5)股票交易(两次)

1、初始5个状态

2、状态转移

什么都不做,和前一天买入/卖出最大收益+当前操作

核心代码:

dp0[0]=0

        dp1[0]=-prices[0]

        dp2[0]=0

        dp3[0]=-prices[0]

        dp4[0]=0


        for i in range(1,k):

            dp0[i]=dp0[i-1]

            dp1[i]=max(dp1[i-1],dp0[i-1]-prices[i])

            dp2[i]=max(dp2[i-1],dp1[i-1]+prices[i])

            dp3[i]=max(dp3[i-1],dp2[i-1]-prices[i])

            dp4[i]=max(dp4[i-1],dp3[i-1]+prices[i])


        return dp4[k-1]


动态规划总结:

https://leetcode-cn.com/problems/coin-change/solution/yi-pian-wen-zhang-chi-tou-bei-bao-wen-ti-sq9n/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容