【力扣】股票问题系列

【力扣】股票问题系列

Leetcode 0121 买卖股票的最佳时机

题目描述:Leetcode 0121 买卖股票的最佳时机

在这里插入图片描述

分析

  • 本题的考点:数组

  • 在遍历的过程中,假设当前遍历到prices[i],记录之前股票的最低价minp,更新获得的最大利润res,并用prices[i]更新最低价minp

代码

  • C++
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int res = 0;
        for (int i = 0, minp = INT_MAX; i < prices.size(); i++) {
            res = max(res, prices[i] - minp);
            minp = min(minp, prices[i]);
        }
        return res;
    }
};
  • Java
class Solution {
    public int maxProfit(int[] prices) {
        int res = 0;
        for (int i = 0, minp = Integer.MAX_VALUE; i < prices.length; i++) {
            res = Math.max(res, prices[i] - minp);
            minp = Math.min(minp, prices[i]);
        }
        return res;
    }
}

时空复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n)n为数组长度。

  • 空间复杂度: O ( 1 ) O(1) O(1)

Leetcode 0122 买卖股票的最佳时机II

题目描述:Leetcode 0122 买卖股票的最佳时机II

在这里插入图片描述

分析

  • 本题的考点:贪心

  • 买入前必须先卖出,但是可以同一天内进行这两种操作,这样操作相当于没有收益。

  • 如果一笔交易在第i天买入,第j天卖出,则可以拆成等价的一天天的交易,如下图:

在这里插入图片描述

  • 这样的每笔交易都可以拆成相邻两天的小的交易,因此对于n天,我们考虑可以进行的n-1次小的交易的最大值。如果有收益的话进行,没有收益的话不操作,收益为0。

代码

  • C++
class Solution {
public:
    int maxProfit(vector<int> &prices) {
        int res = 0;
        for (int i = 0; i + 1 < prices.size(); i++)
            res += max(0, prices[i + 1] - prices[i]);
        return res;
    }
};
  • Java
class Solution {
    public int maxProfit(int[] prices) {
        int res = 0;
        for (int i = 0; i + 1 < prices.length; i++)
            res += Math.max(0, prices[i + 1] - prices[i]);
        return res;
    }
}

时空复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n)n为数组长度。

  • 空间复杂度: O ( 1 ) O(1) O(1)

Leetcode 0123 买卖股票的最佳时机III

题目描述:Leetcode 0123 买卖股票的最佳时机III

在这里插入图片描述

分析

  • 本题的考点:数组、前后缀分解

  • 因为进行两次交易,所以我们可以枚举两次交易的分界点,分别求出每次交易的最大值,相加就是对于当前分界点能获得的最大收益。

  • 对于每个分界点,都有一个最大收益,这些最大收益的最大值就是最终的结果。

  • 对于求一次交易的最大值,可以参考Leetcode 0121 买卖股票的最佳时机的做法。

  • 我们可以枚举第二次买入的时间i,这样我们只要求出前i-1天进行一次交易的最大收益f[i-1],再加上从第i天开始进行一次交易的最大收益即可。

  • 数组f的求解按照Leetcode 0121 买卖股票的最佳时机的方式递推一遍即可。后一次交易可以反向递推一次,当考察第i天时,基于从i+1天到最后一天的最大股价maxp,然后maxp-prices[i]就是当前后一次交易的最大收益。

  • 为了方便,这里下标从1开始。

代码

  • C++
class Solution {
public:
    int maxProfit(vector<int> &prices) {
        int n = prices.size();
        vector<int> f(n + 2);
        for (int i = 1, minp = INT_MAX; i <= n; i++) {
            f[i] = max(f[i - 1], prices[i - 1] - minp);
            minp = min(minp, prices[i - 1]);
        }

        int res = 0;
        for (int i = n, maxp = 0; i; i--) {
            res = max(res, maxp - prices[i - 1] + f[i - 1]);
            maxp = max(maxp, prices[i - 1]);
        }
        return res;
    }
};
  • Java
class Solution {
    public int maxProfit(int[] prices) {
        int n = prices.length;
        // f[i]代表1~i天进行一次交易的最大收益
        int[] f = new int[n + 5];
        for (int i = 1, minp = Integer.MAX_VALUE; i <= n; i++) {
            f[i] = Math.max(f[i - 1], prices[i - 1] - minp);
            minp = Math.min(minp, prices[i - 1]);
        }

        int res = 0;
        for(int i = n, maxp = 0; i > 0; i--) {
            res = Math.max(res, maxp - prices[i - 1] + f[i - 1]);
            maxp = Math.max(maxp, prices[i - 1]);
        }
        return res;
    }
}

时空复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n)n为数组长度。
  • 空间复杂度: O ( n ) O(n) O(n)

Leetcode 0188 买卖股票的最佳时机 IV

题目描述:Leetcode 0188 买卖股票的最佳时机 IV

在这里插入图片描述

分析

  • 本题的考点:动态规划

  • 本题是动态规划中的状态机模型。令n=prices.length

  • k ≥ n / 2 k \ge n / 2 kn/2时,本题就转变为了Leetcode 0122 买卖股票的最佳时机II,用这一题的做法求解即可。

  • 否则的话需要使用状态机模型。分析如下:

  • f(i,j) 表示第i天,交易完成了j次股票,且当天不持有股票的最大收益;g(i,j)表示第i天,交易完成了j次股票,且当天持有股票的最大收益。下图中分别用0、1表示这两种状态。

在这里插入图片描述

  • 因为只有一个起点,所以初始状态 f ( 0 , 0 ) = 0 , g ( 0 , 0 ) = − i n f f(0, 0)=0, g(0, 0)=-inf f(0,0)=0,g(0,0)=inf,其余都为负无穷。

  • 状态转移:

    (1) f ( i , j ) = m a x ( f ( i − 1 , j ) , g ( i − 1 , j − 1 ) + p r i c e [ i ] ) f(i, j) = max(f(i-1, j), g(i-1, j-1)+price[i]) f(i,j)=max(f(i1,j),g(i1,j1)+price[i])

    (2) g ( i , j ) = m a x ( g ( i − 1 , j ) , f ( i − 1 , j ) − p r i c e [ i ] ) g(i, j) = max(g(i-1, j), f(i-1, j)-price[i]) g(i,j)=max(g(i1,j),f(i1,j)price[i])

  • 最终的答案应该是: m a x ( f ( n , i ) ) , 0 ≤ i ≤ k max(f(n, i)), 0 \le i \le k max(f(n,i)),0ik

  • 类似于01背包问题,因为每次我们只会用到上一行的值,可以用滚动数组优化,进一步可以优化成一维。具体细节可以参考:背包九讲

代码

  • C++
int f[101], g[101];  // f存储最后持有现金的结果,g存储最后持有股票的结果,0<=k<=100

class Solution {
public:
    int maxProfit(int k, vector<int> &prices) {

        int n = prices.size();
        if (k >= n / 2) {  // Leetcode 0112
            int res = 0;
            for (int i = 0; i + 1 < n; i++)
                res += max(0, prices[i + 1] - prices[i]);
            return res;
        }

        memset(f, -0x3f, sizeof f);
        memset(g, -0x3f, sizeof g);
        f[0] = 0;
        int res = 0;
        for (int i = 1; i <= n; i++)
            for (int j = k; j >= 0; j--) {  // 因为需要用到之前的信息
                if (j) f[j] = max(f[j], g[j - 1] + prices[i - 1]);
                g[j] = max(g[j], f[j] - prices[i - 1]);
            }
        for (int i = 1; i <= k; i++) res = max(res, f[i]);
        return res;
    }
};
  • Java
class Solution {

    static final int INF = 0x3f3f3f3f;
    int[] f = new int[101], g = new int[101];

    public int maxProfit(int k, int[] prices) {

        int n = prices.length;
        if (k >= n / 2) {
            int res = 0;
            for (int i = 0; i + 1 < n; i++) res += Math.max(0, prices[i + 1] - prices[i]);
            return res;
        }

        Arrays.fill(f, -INF);
        Arrays.fill(g, -INF);
        f[0] = 0;
        for (int i = 1; i <= n; i++)
            for (int j = k; j >= 0; j--) {
                g[j] = Math.max(g[j], f[j] - prices[i - 1]);
                if (j > 0) f[j] = Math.max(f[j], g[j - 1] + prices[i - 1]);
            }
        int res = 0;
        for (int i = 0; i <= k; i++) res = Math.max(res, f[i]);
        return res;
    }
}

时空复杂度分析

  • 时间复杂度: O ( n × k ) O(n \times k) O(n×k)n为数组长度。

  • 空间复杂度: O ( 1 ) O(1) O(1)

Leetcode 0309 最佳买卖股票时机含冷冻期

题目描述:Leetcode 0309 最佳买卖股票时机含冷冻期

在这里插入图片描述

分析

  • 本题的考点:动态规划

  • 本题是动态规划中的状态机模型。令n=prices.length

  • 定义一个二维数组f,第一维表示天数,从0开始,第二维的含义如下:

f[i][0]: 手上不持有股票,并且不在冷冻期中的累计最大收益
f[i][1]: 手上持有股票的最大收益
f[i][2]: 手上不持有股票,并且处于冷冻期中的累计最大收益
  • 状态转移如下:
f[i][0] = max(f[i - 1][0], f[i - 1][2]);  // i-1天非冷冻期不持有股票;i-1天冷冻期不持有股票
f[i][1] = max(f[i - 1][1], f[i - 1][0] - prices[i]);  // i-1天手持股票;i-1天非冷冻期不持有股票然后买入
f[i][2] = f[i - 1][1] + prices[i];  // 只有卖股票后才能处于冷冻期

代码

  • C++
class Solution {
public:
    int maxProfit(vector<int> &prices) {

        if (prices.empty()) return 0;
        int n = prices.size();
        vector<vector<int>> f(n, vector<int>(3));
        f[0][1] = -prices[0], f[0][0] = 0;
        for (int i = 1; i < n; i++) {
            f[i][0] = max(f[i - 1][0], f[i - 1][2]);
            f[i][1] = max(f[i - 1][1], f[i - 1][0] - prices[i]);
            f[i][2] = f[i - 1][1] + prices[i];
        }
        return max(f[n - 1][0], f[n - 1][2]);
    }
};
  • Java
class Solution {
    public int maxProfit(int[] prices) {

        int n = prices.length;
        if (n == 0) return 0;
        int[][] f = new int[n][3];
        f[0][1] = -prices[0];
        f[0][0] = 0;
        for (int i = 1; i < n; i++) {
            f[i][0] = Math.max(f[i - 1][0], f[i - 1][2]);
            f[i][1] = Math.max(f[i - 1][1], f[i - 1][0] - prices[i]);
            f[i][2] = f[i - 1][1] + prices[i];
        }
        return Math.max(f[n - 1][0], f[n - 1][2]);
    }
}

时空复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n)n为数组长度。

  • 空间复杂度: O ( n ) O(n) O(n)

Leetcode 0714 买卖股票的最佳时机含手续费

题目描述:Leetcode 0714 买卖股票的最佳时机含手续费

在这里插入图片描述

分析

  • 本题的考点:动态规划

  • 本题是动态规划中的状态机模型。令n=prices.length

  • 定义一个二维数组f,第一维表示天数,从1开始,第二维的含义如下:f[i][0]: 手上不持有股票,f[i][1]: 手上持有股票的最大收益。

  • 初始状态: f [ 0 ] [ 0 ] = 0 , f [ 0 ] [ 1 ] = − i n f f[0][0]=0, f[0][1]=-inf f[0][0]=0,f[0][1]=inf。负无穷表示不合法状态。

  • 状态转移如下:

    (1) f [ i ] [ 0 ] = m a x ( f [ i − 1 ] [ 0 ] , f [ i − 1 ] [ 1 ] + p r i c e s [ i ] ) f[i][0]=max(f[i-1][0], f[i-1][1]+prices[i]) f[i][0]=max(f[i1][0],f[i1][1]+prices[i])

    (2) f [ i ] [ 1 ] = m a x ( f [ i − 1 ] [ 1 ] , f [ i − 1 ] [ 1 ] − p r i c e s [ i ] − f e e ) f[i][1]=max(f[i-1][1], f[i-1][1]-prices[i]-fee) f[i][1]=max(f[i1][1],f[i1][1]prices[i]fee)

  • 或者状态转移也可以写成:

    (1) f [ i ] [ 0 ] = m a x ( f [ i − 1 ] [ 0 ] , f [ i − 1 ] [ 1 ] + p r i c e s [ i ] − f e e ) f[i][0]=max(f[i-1][0], f[i-1][1]+prices[i]-fee) f[i][0]=max(f[i1][0],f[i1][1]+prices[i]fee)

    (2) f [ i ] [ 1 ] = m a x ( f [ i − 1 ] [ 1 ] , f [ i − 1 ] [ 1 ] − p r i c e s [ i ] ) f[i][1]=max(f[i-1][1], f[i-1][1]-prices[i]) f[i][1]=max(f[i1][1],f[i1][1]prices[i])

  • 可以加入滚动数组优化空间。

代码

  • C++
class Solution {
public:
    int maxProfit(vector<int>& prices, int fee) {
        int n = prices.size(), INF = 1e8;
        vector<vector<int>> f(2, vector<int>(2, -INF));
        f[0][0] = 0;
        int res = 0;
        for (int i = 1; i <= n; i++) {
            f[i & 1][0] = max(f[i - 1 & 1][0], f[i - 1 & 1][1] + prices[i - 1]);
            f[i & 1][1] = max(f[i - 1 & 1][1], f[i - 1 & 1][0] - prices[i - 1] - fee);
            res = max(res, f[i & 1][0]);
        }
        return res;
    }
};
  • Java
class Solution {
    public int maxProfit(int[] prices, int fee) {
        int n = prices.length, INF = (int)1e8;
        int[][] f = new int[2][2];
        f[0][0] = 0; f[0][1] = -INF;
        int res = 0;
        for (int i = 1; i <= n; i++) {
            f[i & 1][0] = Math.max(f[i - 1 & 1][0], f[i - 1 & 1][1] + prices[i - 1] - fee);
            f[i & 1][1] = Math.max(f[i - 1 & 1][1], f[i - 1 & 1][0] - prices[i - 1]);
            res = Math.max(res, f[i & 1][0]);
        }
        return res;
    }
}

时空复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n)n为数组长度。

  • 空间复杂度: O ( 1 ) O(1) O(1)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值