代码随想录第四十九天——买卖股票的最佳时机,买卖股票的最佳时机||

leetcode 121. 买卖股票的最佳时机

题目链接:买卖股票的最佳时机
本题股票只能买卖一次

方法一:贪心

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int low = INT_MAX;
        int result = 0;
        for (int i = 0; i < prices.size(); i++) {
            low = min(low, prices[i]);  // 取最左最小价格
            result = max(result, prices[i] - low); // 直接取最大区间利润
        }
        return result;
    }
};

时间复杂度:O(n)
空间复杂度:O(1)

方法二:动态规划

  1. 确定dp数组以及下标的含义
    dp[i][0] 表示第i天持有股票所得最多现金,
    dp[i][1] 表示第i天不持有股票所得最多现金
  2. 确定递推公式

(1)第i天持有股票,dp[i][0]可以由两个状态推出:

  • 第i-1天就持有股票,那么就保持现状,所得现金就是昨天持有股票的所得现金 dp[i - 1][0]
  • 第i天买入股票,所得现金就是买入今天的股票后所得现金 -prices[i]
    dp[i][0] = max(dp[i - 1][0], -prices[i])

(2)第i天不持有股票,dp[i][1]由两个状态推出来:

  • 第i-1天就不持有股票,那么就保持现状,所得现金就是昨天不持有股票的所得现金 dp[i - 1][1]
  • 第i天卖出股票,所得现金就是按照今天股票价格卖出后所得现金 prices[i] + dp[i - 1][0]
    dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0])
  1. dp数组初始化
    dp[0][0]表示第0天持有股票,所以dp[0][0] -= prices[0]
    dp[0][1]表示第0天不持有股票,所以dp[0][1] = 0
  2. 确定遍历顺序
    dp[i]都是由dp[i - 1]推导出来,所哟从前向后遍历
  3. 举例推导dp数组
    输入[7,1,5,3,6,4],
    dp[i][0]:-7 -1 -1 -1 -1 -1
    dp[i][1]: 0 0 4 4 5 5
    dp[5][1]是最终结果,因为不持有股票状态所得金钱一定比持有股票状态得到的多
版本一:
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int len = prices.size();
        if (len == 0) return 0;
        vector<vector<int>> dp(len, vector<int>(2));
        dp[0][0] -= prices[0];
        dp[0][1] = 0;
        for (int i = 1; i < len; i++) {
            dp[i][0] = max(dp[i - 1][0], -prices[i]);
            dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);
        }
        return dp[len - 1][1];
    }
};

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

版本二:

dp[i]只是依赖于dp[i - 1]的状态,所以只需要记录当前天和前一天的dp状态就可以了,可以简化为滚动数组

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int len = prices.size();
        vector<vector<int>> dp(2, vector<int>(2)); // 注意这里只开辟了一个2 * 2大小的二维数组
        dp[0][0] -= prices[0];
        dp[0][1] = 0;
        for (int i = 1; i < len; i++) {
            dp[i % 2][0] = max(dp[(i - 1) % 2][0], -prices[i]);
            dp[i % 2][1] = max(dp[(i - 1) % 2][1], prices[i] + dp[(i - 1) % 2][0]);
        }
        return dp[(len - 1) % 2][1];
    }
};

时间复杂度:O(n)
空间复杂度:O(1)

leetcode 122. 买卖股票的最佳时机II

题目链接:买卖股票的最佳时机||
本题与上一题的区别是股票可以买卖多次
递推公式如下:

(1)第i天持有股票,dp[i][0]可以由两个状态推出:

  • 第i-1天就持有股票,那么就保持现状,所得现金就是昨天持有股票的所得现金 dp[i - 1][0]
  • 第i天买入股票,所得现金就是买入今天的股票后所得现金dp[i - 1][1] - prices[i] - prices[i](与上一题唯一的区别)
    dp[i][0] = max(dp[i - 1][0],dp[i - 1][1] - prices[i] - prices[i])

(2)第i天不持有股票,dp[i][1]由两个状态推出来:

  • 第i-1天就不持有股票,那么就保持现状,所得现金就是昨天不持有股票的所得现金 dp[i - 1][1]
  • 第i天卖出股票,所得现金就是按照今天股票价格卖出后所得现金 prices[i] + dp[i - 1][0]
    dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0])

版本一:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int len = prices.size();
        vector<vector<int>> dp(len, vector<int>(2, 0));
        dp[0][0] -= prices[0];
        dp[0][1] = 0;
        for (int i = 1; i < len; i++) {
            dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]); //注意与上一题的区别
            dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]);
        }
        return dp[len - 1][1];
    }
};

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

版本二:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int len = prices.size();
        vector<vector<int>> dp(2, vector<int>(2)); // 注意这里只开辟了一个2 * 2大小的二维数组
        dp[0][0] -= prices[0];
        dp[0][1] = 0;
        for (int i = 1; i < len; i++) {
            dp[i % 2][0] = max(dp[(i - 1) % 2][0], dp[(i - 1) % 2][1] - prices[i]);
            dp[i % 2][1] = max(dp[(i - 1) % 2][1], prices[i] + dp[(i - 1) % 2][0]);
        }
        return dp[(len - 1) % 2][1];
    }
};

时间复杂度:O(n)
空间复杂度:O(1)

你可能感兴趣的:(动态规划,数据结构,算法)