《极客时间--算法面试》--动态规划

题目:70、爬楼梯

思路:

  一、采用回溯法,递归+记忆化

  二、采用动态规划,时间复杂度为O(n),采用递推的方式

    要找到DP的状态和DP方程。

  

代码(动态规划):

class Solution(object):
    def climbStairs(self, n):
        """
        :type n: int
        :rtype: int
        """
        '''   
        方式一:传统的方式
        if n==0 or n==1 or n==2:                #边界值判定
            return n                            
        men = [1,2]                             #递推初始值
        for i in range(2,n):                    #从第二个开始到最后
            men.append(men[i-1]+men[i-2])       #将前面两个值相加最为后一个值
        return men[n-1]                         #返回最后的一个结果
        '''
        '''方式二:python的编码方式较为简洁,直接赋值的'''
        x,y = 1,1
        for _ in range(1,n):
            x,y = y,x+y
        return y

题目:120、三角形最小路径和

思路:

  一、回溯

  二、动态规划

    从底层倒推,明确状态转移方程和初始状态。

    初始状态是最后一层,转移方程是相邻节点的最小值和当前值相加作为下一个状态的值。

代码:

class Solution(object):
    def minimumTotal(self, triangle):
        """
        :type triangle: List[List[int]]
        :rtype: int
        """
        if not triangle:                                        #边界判断
            return 0
        res = triangle[-1]                                      #初始状态为最后层
        for i in range(len(triangle)-2,-1,-1):                  #从底层到上层进行遍历
            for j in range(len(triangle[i])):                   #每一层从左往右遍历
                res[j] = min(res[j],res[j+1])+triangle[i][j]    #当前节点的相邻节点之间最小值加上当前节点
        return res[0]                                           #最终的结果值就是最顶层的数

  需要一个一维的数组进行状态压缩。

题目:152乘积最大子序列

思路:

  一、采用递归的思路,暴力解决

    采用递归的思路但采用循环的方式编码。对每一个值进行乘积,将当前最大值进行保存起来,如果与当前的乘积小于前面值就赋值为1.最终返回最大的那个值即可。

  二、采用动态规划,采用递推的方式

    一、状态的定义,一个二维方程,存放正向最大值和负向最小值,两个负数相乘会变正数。

    二、状态方程,最大和最小的值,是比较当前值和当前值和前面乘积的乘积。

代码:

class Solution(object):
    def maxProduct(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if nums is None: return 0                                       #边界判断
        dp = [[0 for _ in range(2)]for _ in range(2)]                   #定义状态,二维数组,存放正向最大和负向最小
        dp[0][1],dp[0][0],res = nums[0],nums[0],nums[0]                 #状态初始值,从第一个值开始
        for i in range(1,len(nums)):                                    #从第二个值开始遍历
            x,y = i%2,(i-1)%2                                           #0,1周期性调控
            dp[x][0] = max(dp[y][0]*nums[i],dp[y][1]*nums[i],nums[i])   #正向最大值
            dp[x][1] = min(dp[y][0]*nums[i],dp[y][1]*nums[i],nums[i])   #负向最小值
            res = max(res,dp[x][0])                                     #每次都保存最大的值,最终返回
        return res

  以下题目买卖股票的最佳时机系列题目均采用动态规划思路去做,明确动态规划的两个基本点:定义状态、状态转移方程和最终的目标结果值。以下思路是通用的泛华思路,定义了三个状态,根据具体的需求再进行细微修改。

  明确状态含义:

    dp[i][j][k]:第i天的最大收益第k次交易的最大收益

    i:第i天【0,n-1】

    j:手上是否持有【0、1】代表手上只能持有一股,可以多股

    k:第k次交易【0,k】

    如果是冷冻时期可以在加状态,比如是否冷冻期,取值范围是0、1等。

  初始状态:

    

  状态转义方程:

    通俗讲:在考虑上次交易的前提下,根据手上是否有股票分别作出行动,由于只有两种情况,即是否持有,后期可以改为

      手上有股票:保持当前的股票和卖掉手上的股票的最大值

      手上没有股票:保持手上没有股票和买入当前饿股票的最大值

  三个循环进行遍历,第一个循环遍历第几天,第二个循环遍历第几次买卖。第三个循环根据手上的股票个数进行操作。针对第一题只有一个股票,后面多个股票,细微修改。

  最终的结果值是最后一天股票操作后在这k次中最大的一个利润值。

股票买卖题目:121股票买卖的最佳时机I

只能进行一次交易

思路:

  

代码:

股票买卖题目:122股票买卖的最佳时机II

无数次交易

思路:

代码:

股票买卖题目:123股票买卖的最佳时机III

只能两次交易

思路:

代码:

股票买卖题目:188股票买卖的最佳时机IV

K次交易

思路:

代码:

股票买卖题目:309最佳股票买卖的最佳时机含冷冻期

两次交易中间会有限制

思路:

代码:

股票买卖题目:714股票买卖的最佳时机含手续费

思路:

代码:

原文地址:https://www.cnblogs.com/missidiot/p/10999081.html