《剑指offer》Python题解:动态规划(一)

声明:《剑指offer》系列几乎所有的分享都与leetcode里面代码分享者Krahets有关,他是主要贡献者,里面会有我的一些个人总结和理解,请大家多指教。

一、 连续子数组的最大和

leetcode 《剑指offer》:42
1、题干

输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。要求时间复杂度为O(n)。

2、示例

输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

3、解题思路

(1)状态定义:设动态规划列表dp,dp[i]代表元素nums[i]为结尾的连续子数组最大和。(动态规划问题都需要状态定义,也可称之为动态规划列表定义,在这个列表里面存储的值与题干紧密相关)
(2)转移方程:若 dp[i-1]≤0 ,说明 dp[i - 1]对dp[i] 产生负贡献,即 dp[i-1] + nums[i] 还不如 nums[i] 本身大。所以知道状态转移方程为:
在这里插入图片描述
在这里插入图片描述
(3)初始状态: dp[0] = nums[0],即以 nums[0]结尾的连续子数组最大和为 nums[0]。
(4)返回值:返回 dpdp 列表中的最大值,代表全局最大值。

4、复杂度分析:

(1)时间复杂度 O(N): 线性遍历数组 numsnums 即可获得结果,使用 O(N)时间。
(2)空间复杂度 O(1):由于 dp[i]只与 dp[i-1]和 nums[i]有关系,因此可以将原数组 nums 用作 dp列表,即直接在 nums上修改即可。

5、Python代码:
def f(nums):
	for i in range(1, len(nums)):
		nums[i] += max(nums[i-1], 0)
	return max(nums)
6、代码讲解:

(1)因为没有使用额外的存储空间,所以直接在nums上建立动态规划列表dp(即dp和nums共用同一块存储空间)
所以nums +=相当于dp[i] +=
(2)根据状态转移方程,dp[i-1]和0作比较, 即nums[i-1]和0作比较,选择较大的值与dp[i](即nums[i])相加
(3)返回dp中的最大值,即max(nums)

7、动态规划解题流程:

(1)判断是不是动态规划类型题目(核心词:“最”,可以对照后面的例题)
(2)状态定义——>转移方程——>初始值——>返回值(dp)
(3)编程实现(max)

二、买卖的最佳时机

leetcode 《剑指offer》:63
1、题干

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。
注意:你不能在买入股票前卖出股票。

2、示例

(1)输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。

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

3、解题思路

又是“最”+数组的问题,动态规划。
(1)状态定义:状态转移列表dp[i]表示第i天卖出的最大受益
(2)转移矩阵:这里不需要重建状态转移列表,只需要保留最大值。即,如果第i天的卖出收益最大,则保留最大值;
公式为:dp[i] = max(dp[i-1], nums[i] - min(nums[:i]))
(3)初始状态:dp[0] = 0
(4)返回值:最后保留的值
值得注意的是:如果我们每次计算dp[i-1]会有大量的重复计算,我们可以用profit表示前i-1天最大受益, 那么第i天的收益只需要与profit比较就好了;同理,也没必要重复计算前i-1天的买入最小值,使用cost代替。这样会降低时间复杂度。

4、Python代码
def f(nums):
cost, profit = float('+inf'), 0
for price in prices:
	cost = min(price, cost)
	profit = max(profit, price-cost)
return profit

在这里插入图片描述
dp在变化过程中,不是以列表的形式存在的,是以最大值的数值形式存在的。动态规划类型问题常有两种返回值情况(1)最大值(2)列表求和或者max(alist),当元素之间有相关性的时候常采用后一种方式。元素间无相关性,如本题,只需保留最大值。

5、复杂度分析

(1)时间复杂度O(n):只需遍历一次列表
(2)空间复杂度O(1):状态转移结果采用常数保存。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值