股票交易问题-算法题

买卖股票最佳时机


只买卖一次

只买卖一次的话,只需要在最低点买入,最高点卖出即可。

// 空间复杂度O(1)
// 从左到右
int maxProfit(vector<int>& prices) {
    int n = prices.size();
    if (!n) return 0;
    int ret = 0, minn = prices[0];
    for (int i = 1; i < n; ++i) {
        ret = max(ret, prices[i] - minn);
        minn = min(minn, prices[i]);
    }
    return ret;
}

// 从右到左
int maxProfit(vector<int>& prices) {
    int n = prices.size();
    if (!n) return 0;
    int ret = 0, maxn = prices.back();
    for (int i = n-1; i >= 0; --i) {
        ret = max(ret, maxn - prices[i]);
        maxn = max(maxn, prices[i]);
    }
    return ret;
}

限定买卖2次

根据只能买卖一次的做法,可以选择从左到右和从右到左两种方法,仅需预处理其中一种,然后再从另一边遍历即可。

// O(n),预处理左边,再从右边遍历
int maxProfit(vector<int>& prices) {
    int n = prices.size();
    if (!n) return 0;
    vector<int> left(n);
    int minn = prices[0];
    for (int i = 1; i < n; ++i) {
        left[i] = max(left[i-1], prices[i] - minn);
        minn = min(minn, prices[i]);
    }
    int maxn = prices.back(), ret = 0;
    // 如果必须要买卖2次,ret从0开始;
    // 如果是最多买卖2次,ret从left.back()开始;
    for (int i = n-1; i >= 1; --i) {
        ret = max(ret, maxn - prices[i] + left[i-1]);
        maxn = max(maxn, prices[i]);
    }
    return ret;
}

可买卖任意次

int maxProfit(vector<int>& prices) {
    int n = prices.size();
    int dp[n][2];
    dp[0][0] = 0, dp[0][1] = -prices[0];
    for (int i = 1; i < n; ++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[n-1][0];
}

int maxProfit(vector<int>& prices) {
    int n = prices.size();
    int dp0 = 0, dp1 = -prices[0];
    for (int i = 1; i < n; ++i) {
        int newDp0 = max(dp0, dp1 + prices[i]);
        int newDp1 = max(dp1, dp0 - prices[i]);
        dp0 = newDp0;
        dp1 = newDp1;
    }
    return dp0;
}

int maxProfit(vector<int>& prices) {   
    int ans = 0, n = prices.size();
    for (int i = 1; i < n; ++i)
        ans += max(0, prices[i] - prices[i - 1]);
    return ans;
}

限定最多买卖k次

动态规划:
buy[i][j]表示前i天交易j次,且当前持有股票的最大收益;
sell[i][j]表示前i天交易j次,且当前不持有股票的最大收益;

状态转移方程:
buy[i][j] = max(buy[i-1][j], sell[i-1][j]-prices[i]);
sell[i][j] = max(sell[i-1][j], buy[i-1][j-1]+prices[i]);

注意:
不合理的情况(如前i天交易了大于i/2的次数),设为-inf,将所有由不合理的状态推到出的新的状态也设为-inf;

int maxProfit(int k, vector<int>& prices) {
    if (prices.empty()) return 0;
    int n = prices.size(), kk = min(k, n/2);
    vector<vector<int>> buy(n, vector<int>(kk+1)), sell(buy);
    buy[0][0] = -prices[0];
    for (int i = 1; i <= kk; ++i)
        buy[0][i] = sell[0][i] = -1e9;
    for (int i = 1; i < n; ++i) {
        for (int j = 0; j <= kk; ++j) {
            buy[i][j] = max(buy[i-1][j], sell[i-1][j]-prices[i]);
            if (j) sell[i][j] = max(sell[i-1][j], buy[i-1][j-1]+prices[i]);
        }
    }
    return *max_element(sell[n-1].begin(), sell[n-1].end());
}

空间优化:已知状态转移方程中,当前状态只与前一次交易的状态有关,因此只需要维护一组交易状态即可

int maxProfit(int k, vector<int>& prices) {
    if (prices.empty()) return 0;
    int n = prices.size(), kk = min(k, n/2);
    vector<int> buy(kk+1), sell(buy);
    buy[0] = -prices[0];
    for (int i = 1; i <= kk; ++i)
        buy[i] = sell[i] = -1e9;
    for (int i = 1; i < n; ++i) {
        for (int j = 0; j <= kk; ++j) {
            buy[j] = max(buy[j], sell[j]-prices[i]);
            if (j) sell[j] = max(sell[j], buy[j-1]+prices[i]);   
        }
    }
    return *max_element(sell.begin(), sell.end());
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值