动态规划

剑指offer 42. 连续子数组的最大和

输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
要求时间复杂度为O(n)。
示例1:
输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
提示:

1 <= arr.length <= 10^5
-100 <= arr[i] <= 100

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lian-xu-zi-shu-zu-de-zui-da-he-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        res = nums[0]
        dp = res
        for i in range(1,len(nums)):
            if dp>0:
                dp = dp + nums[i]
            else:
                dp = nums[i]
            res = max(res,dp)
        return res

小结

「动态规划」 每次保存上次的连续子数组的最大值。dp>0时,可一直计算连续的数的和;dp<0时,就意味着上一个连续的子数组不会有最大值了,需要重新更新当前子数组。dp的值每更新一次,最大值就要判断一次。

455.分发饼干

假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。

对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。

 
示例 1:

输入: g = [1,2,3], s = [1,1]
输出: 1
解释: 
你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。
虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。
所以你应该输出1。
示例 2:

输入: g = [1,2], s = [1,2,3]
输出: 2
解释: 
你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。
你拥有的饼干数量和尺寸都足以让所有孩子满足。
所以你应该输出2.

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/assign-cookies
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution:
    def findContentChildren(self, g: List[int], s: List[int]) -> int:
        if len(s)==0:
            return 0
        g.sort()
        s.sort()
        res = 0
        g_lenth = len(g)
        s_lenth = len(s)
        i,j=0,0
        while i<g_lenth and j<s_lenth:
            if s[j]>= g[i]:
                res+=1
                i+=1
                j+=1
            else:
        return res

剑指 Offer 63. 股票的最大利润

假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少?


示例 1:

输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
     注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
示例 2:

输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/gu-piao-de-zui-da-li-run-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        if len(prices)==0:
            return 0
        profit,min_cost = 0,prices[0]
        for i in range(1,len(prices)):
            cur_profit = prices[i]-min_cost
            profit = max(profit,cur_profit)
            min_cost=min(min_cost,prices[i])
        return profit
小结

可以取得的最大利润为前 i − 1 i-1 i1天可以取得的最大收益与今天可以取得的最大收益的大值。即: p r o f i t = m a x ( p r o f i t , p r i c e s [ i ] − m i n ( p r i c e s [ 0 : i ] ) ) profit=max(profit,prices[i]-min(prices[0:i])) profit=max(profit,prices[i]min(prices[0:i]))。在实际计算的时候使用 c o s t m i n cost_{min} costmin来保存前i-1天买入股票的最小值。则:动态规划的转移方程为: p r o f i t = m a x ( p r o f i t , p r i c e s [ i ] − c o s t m i n ) profit=max(profit,prices[i]-cost_{min}) profit=max(profit,prices[i]costmin) 其中初始化: p r o f i t = 0 , c o s t m i n = p r i c e s [ 0 ] profit=0,cost_{min}=prices[0] profit=0,costmin=prices[0]

剑指 Offer 47. 礼物的最大价值

在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?

示例 1:

输入: 
[
  [1,3,1],
  [1,5,1],
  [4,2,1]
]
输出: 12
解释: 路径 1→3→5→2→1 可以拿到最多价值的礼物

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/li-wu-de-zui-da-jie-zhi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution:
    def maxValue(self, grid: List[List[int]]) -> int:
        for i in range(0,len(grid)):
            for j in range(0,len(grid[0])):
                if i!=0 and j==0:
                    grid[i][j]=grid[i-1][j]+grid[i][j]
                if i==0 and j!=0:
                    grid[i][j]=grid[i][j-1]+grid[i][j]
                if i!=0 and j!=0:
                    grid[i][j]=max(grid[i-1][j],grid[i][j-1])+grid[i][j]
        return grid[-1][-1]
小结

为了保证时间复杂度为 O ( M N ) O(MN) O(MN),空间复杂度为 O ( 1 ) O(1) O(1)。必然使用动态规划。保存前阶段取得的最优解。从左上角到右下角,在拿礼物的过程中只能往右和往下移动,所以有如下转移方程:

d p [ i ] [ j ] = { m a x ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] ) + g r i d [ i ] [ j ] i ≠ 0 , j ≠ 0 d p [ i ] [ j − 1 ] + g r i d [ i ] [ j ] i = 0 , j ≠ 0 d p [ i − 1 ] [ j ] + g r i d [ i ] [ j ] i ≠ 0 , j = 0 g r i d [ i ] [ j ] i = 0 , j = 0 dp[i][j]=\begin{cases}max(dp[i-1][j],dp[i][j-1])+grid[i][j]&i\neq0,j\neq0\\dp[i][j-1]+grid[i][j]&i=0,j\neq0\\dp[i-1][j]+grid[i][j]&i\neq0,j=0\\grid[i][j]&i=0,j=0 \end{cases} dp[i][j]=max(dp[i1][j],dp[i][j1])+grid[i][j]dp[i][j1]+grid[i][j]dp[i1][j]+grid[i][j]grid[i][j]i=0,j=0i=0,j=0i=0,j=0i=0,j=0

*剑指 Offer 14- I. 剪绳子

给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m-1] 。请问 k[0]*k[1]*...*k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

示例 1:

输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1
示例 2:

输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
提示:

2 <= n <= 58

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/jian-sheng-zi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution:
    def cuttingRope(self, n: int) -> int:
        if n <=3:
            return n-1
        # 创建一个长度为n+1的list,初始化元素为0
        dp = [0]*(n+1)
        # dp[n]=max(dp[n-1]*1,dp[n-2]*2,...),其中dp[a]*b中a>=b
        dp[2]=2
        dp[3]=3
        for i in range(4,n+1):
            a,b=i-1,1
            cur_max=0 # 存放计算当前dp[i]的值得最大值
            while a>=b:
                cur_max=max(cur_max,dp[a]*b)
                a=a-1
                b=b+1
            dp[i]=cur_max
        return dp[n]

小结

问题等价于 { n = n 1 + n 2 + . . . + n m m a x ( n 1 × n 2 × . . . × n m ) = ? \begin{cases} n=n_1+n_2+...+n_m\\ max(n_1\times n_2\times ...\times n_m)=? \end{cases} {n=n1+n2+...+nmmax(n1×n2×...×nm)=?
d p dp dp为一个长度为 n + 1 n+1 n+1 l i s t list list d p [ i ] dp[i] dp[i]代表长度为 i i i的绳子切分后对应的各段长度乘积的最大值。很显然 d p [ 2 ] = 1 , d p [ 3 ] = 2 dp[2]=1,dp[3]=2 dp[2]=1,dp[3]=2
动态规划的转移方程为: d p [ n ] = m a x ( d p [ n − 1 ] ∗ 1 , d p [ n − 2 ] ∗ 2 , . . . ) dp[n]=max(dp[n-1]*1,dp[n-2]*2,...) dp[n]=max(dp[n1]1,dp[n2]2,...)形式 “ d p [ a ] ∗ b " “dp[a]*b" dp[a]b" a > = b a>=b a>=b。在这个转移方程中,我们令 d p [ 2 ] = 2 , d p [ 3 ] = 3 dp[2]=2,dp[3]=3 dp[2]=2,dp[3]=3。意义是:切分的最小段的长度为2或3。原因是:要获得最大的乘积,长度为1的段应越少越好,这样的线段的数量最多为1。转移方程也很好理解,长度为n的线段,可以分为1条长度为n-1的线段和1条长度为1的线段,其他情况同理。最后取这些情况的最大值作为长度为n的线段的最优。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值