zoukankan      html  css  js  c++  java
  • 通杀leetcode买卖股票系列

    第一题、121. 买卖股票的最佳时机

    题目

    给定一个数组,它的第 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。

    思路

    如果想要获得最大利润,我们就得寻找一个低点和一个高点,使它们得前后插值最大,那么我们假设在第i天卖出,同时我们记录前i-1天得最低值,遍历更新它们最大差值即可。

    代码

    class Solution {
    public:
        int maxProfit(vector<int>& prices) {
            int ans = 0;
            int minPrice = 0x3f3f3f;
            for(int i=0;i<prices.size();i++)
            {
                minPrice = min(minPrice,prices[i]);
                ans = max(ans,prices[i]-minPrice);
            }
            return ans;
        }
    };

    第二题、122. 买卖股票的最佳时机 II

    题目

    给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

    设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

    注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

    示例 1:

    输入: [7,1,5,3,6,4]
    输出: 7
    解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
      随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
    示例 2:

    输入: [1,2,3,4,5]
    输出: 4
    解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
      注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
      因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
    示例 3:

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

    思路

    第二题变成了可以多次购买,那么想让利润最大那就是只去买涨得部分即可

    代码

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

    第三题、123. 买卖股票的最佳时机 III

    题目

    给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。

    设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。

    注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

    示例 1:

    输入: [3,3,5,0,0,3,1,4]
    输出: 6
    解释: 在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。
      随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。
    示例 2:

    输入: [1,2,3,4,5]
    输出: 4
    解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。  
      注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。  
      因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
    示例 3:

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

    思路

    第三题在第二题的基础上加入了最多购买次数,可以最多购买2次。通过思考可以发现,在没有买股票的时候,对于每一天的选择是买或不买;在已经买了股票的时候,对于每一天的选择是卖或不卖。此时会发现这里的很像0-1背包问题,对于每一个物品,都有放和不放的选择,0-1背包是在状态转移中选择放或不放,同时对背包的容量有限制。已知的0-1背包状态转移方程为

    $dp[i][v] = max(dp[i-1][v],dp[i-1][v-c[i]]+w[i])$

    而这道题目比0-1背包多出一个是否持有股票的限制,(即,不能同时参与多笔交易),所以我们可以多定义一个状态,定义状态$dp[i][k][j]$表示在第i天,购买次数限制为k,目前的股票的持有状态为j的最大利润。

    • 在没有买股票的时候,对于每一天的选择是买或不买,即
      • 买 : $dp[i-1][k][0] - prices[i]$ ——> $dp[i][k+1][1]$
      • 不买:$dp[i-1][k][0]$ ——> $dp[i][k][0]$
    • 已经买了股票的时候,对于每一天的选择是卖或不卖,即
      • 卖:$dp[i-1][k][1] + prices[i]$ ——> $dp[i][k][0]$
      • 不卖:$dp[i-1][k][1]$ ——> $dp[i][k][1]$

     那么整体的状态转移方程为:

    $dp[i][k][0] = max(dp[i-1][k][0],dp[i-1][k][1]+prices[i])$

    $dp[i][k][1] = max(dp[i-1][k][1],dp[i-1][k-1][0]-prices[i])$

    最后考虑边界和初始化问题,在第一天时,只能选择买入,不能卖出。

    代码

    class Solution {
    public:
        int maxProfit(vector<int>& prices) {
            int n = prices.size();
            if(n==0) return 0 ;
            int max_k = 2;
            int dp[n+1][max_k+1][2];
            memset(dp,0,sizeof(dp));
            for(int i=0;i<n;i++)
            {
                for(int k = 1;k<=max_k;k++)
                {
                    if(i==0)
                    {
                        dp[0][k][0] = -prices[i];
                        dp[0][k][1] = 0;
                        continue;
                    }
                    dp[i][k][0] = max(dp[i-1][k-1][1]-prices[i],dp[i-1][k][0]);
                    dp[i][k][1] = max(dp[i-1][k][0]+prices[i],dp[i-1][k][1]);
                }
            }
            int ans = dp[n-1][max_k][1];
            return ans;
        }
    };

    第四题、188. 买卖股票的最佳时机 IV

    题目

    给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。

    设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。

    注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

    示例 1:

    输入: [2,4,1], k = 2
    输出: 2
    解释: 在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2 。
    示例 2:

    输入: [3,2,6,5,0,3], k = 2
    输出: 7
    解释: 在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4 。
      随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。

    思路

    当我拿到第四题时,我笑了,哈哈,这不和第3题差不多吗!改下交易次数不就OK!一提交,傻了,超出内存限制.......

    好吧,那聪明的你想一想,是不是有一个0-1背包优化空间的方法,可以将二维数组变成滚动数组,它的状态转移方程为

    $dp[j] = max(dp[j],dp[j-c[i]]+w[i])$

    那么我们这道题也是可以优化的,优化后的状态转移方程为

    $dp[k][0] = max(dp[k][0],dp[k][1]+prices[i])$

    $dp[k][1] = max(dp[k][1],dp[k-1][0]-prices[i])$

    我们知道,滚动数组最重要的枚举顺序问题,要利用倒叙枚举覆盖旧值。然而这道题正序倒序都可以,这个之后再说。

    代码

    class Solution {
    public:
        int maxProfit(int num, vector<int>& prices) {
             int n = prices.size();
            if(n==0) return 0 ;
            int max_k = min(num,n/2);
            int dp[max_k+1][2];
            memset(dp,0,sizeof(dp));
            for(int i=0;i<n;i++)
            {
                for(int k = 1;k<=max_k;k++)
                {
                    if(i==0)
                    {
                        dp[k][0] = -prices[i];
                        dp[k][1] = 0;
                        continue;
                    }
                    dp[k][0] = max(dp[k-1][1]-prices[i],dp[k][0]);
                    dp[k][1] = max(dp[k][0]+prices[i],dp[k][1]);
                }
            }
            int ans = dp[max_k][1];
            return ans;
        }
    };

    第五题、309. 最佳买卖股票时机含冷冻期

  • 相关阅读:
    05 drf源码剖析之认证
    04 drf源码剖析之版本
    03 drf源码剖析之视图
    02 drf源码剖析之快速了解drf
    OA之为用户设置角色和为用户设置权限
    EasyUI之datagrid的使用
    C#之反射
    EasyUI之Layout布局和Tabs页签的使用
    Memcached的使用
    Log4Net的简单使用
  • 原文地址:https://www.cnblogs.com/simplekinght/p/13190016.html
Copyright © 2011-2022 走看看