• [LeetCode] 动态规划入门题目


    最近接触了动态规划这个厉害的方法,还在慢慢地试着去了解这种思想,因此就在LeetCode上面找了几道比较简单的题目练了练手。

    首先,动态规划是什么呢?很多人认为把它称作一种“算法”,其实我认为把它称作一种“思想”更为合适;利用动态规划去解决问题,其实就是逐步递推的过程,与贪心算法不同,动态规划递推的每一步都要求是当前的最优解(这是很重要的,递推的正确性依赖的就是这一点);利用动态规划解题时,必须自己定义出来状态和状态转移方程。然而,看上去简单,做起来却非常困难,因为解题时的具体形式千差万别,找出问题的子结构以及通过子结构重新构造最优解的过程很难统一。

    经典的动态规划题目有背包问题、硬币问题等等,可以通过这些题目去理解一下这个东西。

    我认为,动态规划最难的就是找出状态方程。同时,个人认为比较难理解的一点是,懂得“前面每一步都是最优解”这个前提。

    废话不多说,直接看看LeetCode上简单的动态规划题目。

    要注意的是,下面的三题都用到了局部最优和全局最优解法:

    1.Jump Game

    原题地址:https://leetcode.com/problems/jump-game/description/

    解法:

    用一个global变量保存到目前为止能跳的最远距离,用一个local变量保存当前一步出发能跳的最远距离,这题里面的状态就是走到每一步时的global[i]值,状态转移方程就是global[i] =max{nums[i] + i, global[i-1]}。当然,写代码的时候用变量代替数组即可。

    class Solution {
    public:
        bool canJump(vector<int>& nums) {
          int reach = 0;
          for (int i = 0; i < nums.size() - 1 && reach >= i; i++) {
              reach = nums[i] + i > reach ? nums[i] + i : reach;
          }
          return reach >= nums.size() - 1;
      }
    };

    2.Maximum Subarray

    原题地址:https://leetcode.com/problems/maximum-subarray/description/

    解法:

    这一题要维护两个变量:global和local,与上面一题一样,local保存包含当前元素的最大值(局部最优),global保存的是所有情况里面的最大值(全局最优)。假设第i步的local[i]和global[i]已知,那么第i+1步的local[i + 1] = max{ nums[i] + local[i], nums[i + 1] },global[i + 1]  = max{global[i], local[i + 1]}。代码如下:

    class Solution {
    public:
        int maxSubArray(vector<int>& nums) {
          int global = nums[0], local = nums[0];
          for (int i = 1; i < nums.size(); i++) {
              local = nums[i] > nums[i] + local ? nums[i] : nums[i] + local;
              global = local > global ? local : global;
          }       
          return global;
      }
    };

    3.Best Time to Buy and Sell Stock

    原题地址:https://leetcode.com/problems/best-time-to-buy-and-sell-stock/description/

    这道题目有两种方法,其实都是动态规划:

    (1)

    class Solution {
    public:
       int maxProfit(vector<int>& prices) {
           if (prices.size() == 0) return 0; 
          int maxPrice = prices[prices.size() - 1];
          int res = 0;
          for (int i = prices.size() - 1; i >= 0; i--) {
              maxPrice = max(maxPrice, prices[i]);
              res = max(res, maxPrice - prices[i]);
          }
          return res;     
      }
    };

    这种解法在这个博客里面讲得很详细:http://www.cnblogs.com/remlostime/archive/2012/11/06/2757434.html

    (2)局部最优和全局最优解法:

    class Solution {
    public:
       int maxProfit(vector<int>& prices) {
          if (prices.size() == 0) return 0;
          int local = 0, global = 0;
          for (int i = 1; i < prices.size(); i++) {
              local = max(0, local + prices[i] - prices[i - 1]);
              global = max(local, global);
          }
          return global;   
      }
    };
    local = max(0, local + prices[i] - prices[i - 1])这一句,我一开始在考虑:为什么不写成local = max(local, local + prices[i] - prices[i - 1])呢?
    后来想了一下,因为假如这样写,有可能得到的就不是包含当前元素的局部最优解了。所以,在“局部最优和全局最优解法”里面,永远不会出现local=local的情况。


    4.Minimum Path Sum
    原题地址:https://leetcode.com/problems/minimum-path-sum/description/
    这道题目不需用到上面的“局部最优和全局最优”解法,只需要每次选出最优的即可。除了边界的元素,其他元素的最优都是 min{min[i - 1][j] + grid[i][j],min[i][j - 1] + grid[i][j]
    }。
    class Solution {
    public:
        int minPathSum(vector<vector<int>>& grid) {
            int ** min  = new int*[grid.size()];
            for (int i = 0; i < grid.size(); i++) {
                min[i] = new int[grid[i].size()];
            }
            min[0][0] = grid[0][0];
            for (int i = 0; i < grid.size(); i++) {
                for (int j = 0; j < grid[i].size(); j++) {
                    if (i == 0 && j == 0) continue;
                    else if (i == 0) min[i][j] = min[i][j - 1] + grid[i][j];
                    else if (j == 0) min[i][j] = min[i - 1][j] + grid[i][j];
                    else min[i][j] = min[i - 1][j] + grid[i][j] < min[i][j - 1] + grid[i][j] ? min[i - 1][j] + grid[i][j] : min[i][j - 1] + grid[i][j] ;
                }
            }
            return min[grid.size() - 1][grid[grid.size() - 1].size() - 1];
            return 0;
        }
    };


    5.Triangle
    地址:https://leetcode.com/problems/triangle/description/

    也是一道典型的dp题目,思想跟上面一题差不多:
    class Solution {
    public:
        int minimumTotal(vector<vector<int>>& triangle) {
            if (triangle.size() == 1) return triangle[0][0];
            int ** min = new int *[triangle.size()];
            for (int i = 0; i < triangle.size(); i++) {
                min[i] = new int[triangle[i].size()];
            }
            min[0][0] = triangle[0][0];
            int res = INT_MAX;
            for (int i = 0; i < triangle.size(); i++) {
                for (int j = 0; j < triangle[i].size(); j++) {
                    if (i == 0 && j == 0) continue;
                    else if (j == 0) min[i][j] = min[i - 1][j] + triangle[i][j];
                    else if (j == triangle[i].size() - 1) min[i][j] = min[i - 1][j - 1] + triangle[i][j];
                    else min[i][j] = min[i - 1][j - 1] + triangle[i][j] < min[i - 1][j] + triangle[i][j] ? min[i - 1][j - 1] + triangle[i][j] : min[i - 1][j] + triangle[i][j];
                    if (min[i][j] < res && i == triangle.size() - 1) {
                        res = min[i][j];
                    }
                }
            }
            return res;
        }
    };
    但这道题有趣的地方在于,空间复杂度可以缩小到O(n):我们把这个三角形倒过来看,便能发现可以通过复用一个一维数组来储存最小值:
    class Solution {
    public:
        int minimumTotal(vector<vector<int>>& triangle) {
            vector<int> min = triangle[triangle.size() - 1];
            for (int i = triangle.size() - 2; i >= 0; i--) {
                for (int j = 0; j <= i; j++) {
                    min[j] = min[j] < min[j + 1] ? min[j] + triangle[i][j] : min[j + 1] + triangle[i][j];
                }    
            }
            return min[0];
        }
    };
    
    
    







  • 相关阅读:
    神经网络与数字货币量化交易系列(1)——LSTM预测比特币价格
    FMZ发明者量化平台回测机制说明
    使用JavaScript实现量化策略并发执行
    数字货币期货与现货JavaScript量化策略代码详解汇总
    极简比特币高频策略机器人
    爬虫爬取币安公告自动出售将要下架币策略
    Deribit交易所 websocket API 连接范例
    极简版OKEX比特币跨期对冲策略
    OKEX websocket API 连接Python范例
    Vmare安装Linux 虚拟机流程
  • 原文地址:https://www.cnblogs.com/fengziwei/p/7612879.html
Copyright © 2020-2023  润新知