动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解。 动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。我们可以用一个表来记录所有已解的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。这就是动态规划法的基本思路。具体的动态规划算法多种多样,但它们具有相同的填表格式。
这是百科上对于动态规划的解释,看起来复杂其实很简单,举个例子:你可以问一个小孩 1 + 1 + 1 = ?,很简单答案是3,那1+1+1+1 = ?,答案也很简单是4,怎样计算更快呢?只需3 + 1即可。我们可以看到如果能记录前一个子问题的结果,避免重复运算,很好运用前一个子问题的结果大大提升效率,这就是动态规划(Dynamic Programming)
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。
注意:你不能在买入股票前卖出股票。
示例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。
依次便利股票价格,随时记录股票价格最小的点,和当前最大的收益。利用的动态规划的思想,记录当前的值,避免重复计算。暴力法费时的原因就是不会记录当前最优的值。
自己的代码
class Solution:
def maxProfit(self, prices: List[int]) -> int:
buy_point = 0
max_profit = -float("inf")
for i in range(1, len(prices)):
if prices[i] < prices[buy_point]:
buy_point = i
else:
max_profit = max(max_profit, prices[i]-prices[buy_point])
if max_profit < 0:
return 0
else:
return max_profit
官方
class Solution:
def maxProfit(self, prices: List[int]) -> int:
minprice = float('inf')
maxprofit = 0
for price in prices:
minprice = min(minprice, price)
maxprofit = max(maxprofit, price - minprice)
return maxprofit
对比
官方代码更加简洁,对比之后才能发现其实我的代码可以更好的优化。
1.对比求最小值和最大值问题上,应用max(arg,arg…,arg)和min(arg,arg,…,arg),既简洁可读性也强。
2.循环里没必要使用 if…else 语句,然后循环可以从0开始。当初想的是利润的正负要分开,其实没要,第一次最大profit为0,之后的负数利润是不可能比0大的。
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和
示例1
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
进阶:
如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。
可以用如下方法解决,详细分析动态规划
暴力法实现的时间复杂度为 O ( n 2 ) O(n^2) O(n2)
动态规划法
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
dy = []
for i in range(len(nums)):
if not dy:
dy.append(nums[i])
else:
dy.append(max(nums[i], dy[i-1] + nums[i]))
return max(dy)
这两道题感觉上是非常相似的,但是第二道题更加复杂,因为要考虑如何去找子问题,所以第二题我并没有独立思考出来。虽然没有思考出来,但是我对动态规划的思想有了更深刻的认识:将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解,可以说第二道题完全就是按照这个思想来的。希望能够利用动态规划的思想独立思考出其他的题目。