leetcode刷题记录13(2023-08-04)【买卖股票的最佳时机(记录前缀最小值) | 买卖股票的最佳时机 II(单调栈) | 买卖股票的最佳时机含冷冻期(动态规划) | 戳气球(动态规划)】

121. 买卖股票的最佳时机

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

示例 1:
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

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

提示:

1 < = p r i c e s . l e n g t h < = 1 0 5 1 <= prices.length <= 10^5 1<=prices.length<=105
0 < = p r i c e s [ i ] < = 1 0 4 0 <= prices[i] <= 10^4 0<=prices[i]<=104

#include<vector>
#include<iostream>

using namespace std;

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

        return maxMoney;
    }
};

int main() {
    vector<int> vec = { 7,1,5,3,6,4 };
    Solution sol;
    int res = sol.maxProfit(vec);
    cout << res;
}

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

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润 。

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

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

示例 3:
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0 。

提示:
1 < = p r i c e s . l e n g t h < = 3 ∗ 1 0 4 1 <= prices.length <= 3 * 10^4 1<=prices.length<=3104
0 < = p r i c e s [ i ] < = 1 0 4 0 <= prices[i] <= 10^4 0<=prices[i]<=104

采用单调栈进行维护,只要股票上涨我就不卖,什么时候跌,什么时候卖,把栈弹空,然后继续维护单调栈。

#include<vector>
#include<stack>
#include<iostream>

using namespace std;

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        stack<int> stk;
        stk.push(prices[0]);
        int res = 0;

        for (int i = 1; i < prices.size(); i++) {
            if (prices[i] < stk.top()) {
                int maxVal = stk.top();
                int minVal = stk.top();
                while (!stk.empty()) {
                    minVal = stk.top();
                    stk.pop();
                }
                res += maxVal - minVal;
            }
            stk.push(prices[i]);
        }

        if (!stk.empty()) {
            int maxVal = stk.top();
            int minVal = stk.top();
            while (!stk.empty()) {
                minVal = stk.top();
                stk.pop();
            }
            res += maxVal - minVal;
        }

        return res;
    }
};

int main() {
    Solution sol;
    vector <int> vec = { 7,1,5,3,6,4 };
    int res = sol.maxProfit(vec);
    cout << res;
}

309. 买卖股票的最佳时机含冷冻期

给定一个整数数组prices,其中第 prices[i] 表示第 i 天的股票价格 。​

设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):

卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例 1:
输入: prices = [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]

示例 2:
输入: prices = [1]
输出: 0

提示:
1 < = p r i c e s . l e n g t h < = 5000 1 <= prices.length <= 5000 1<=prices.length<=5000
0 < = p r i c e s [ i ] < = 1000 0 <= prices[i] <= 1000 0<=prices[i]<=1000

这道题目较为巧妙,对于每一天,只可能任何股票都不拥有,当天买入,当天卖出3种情况,根据这3种情况,进行状态转移即可得到。

不好想,需要带入到股票买卖的场景中来。

关于这道题目主要参考题解:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-with-cooldown/solutions/181734/fei-zhuang-tai-ji-de-dpjiang-jie-chao-ji-tong-su-y/

#include<vector>

using namespace std;

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int dayNum = prices.size();

        vector<vector<int>> dp(dayNum, vector<int>(3));
        // 本来就不持有股票
        dp[0][0] = 0;
        // 第 0 天买入
        dp[0][1] = -prices[0];
        // 当天卖出了
        dp[0][2] = 0;

        for (int i = 1; i < dayNum; i++) {
            dp[i][0] = max(dp[i - 1][0], dp[i - 1][2]);
            dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
            dp[i][2] = dp[i - 1][1] + prices[i];
        }

        return max(dp[dayNum - 1][0], dp[dayNum - 1][2]);
    }
};

312. 戳气球

有 n 个气球,编号为0 到 n - 1,每个气球上都标有一个数字,这些数字存在数组 nums 中。

现在要求你戳破所有的气球。戳破第 i 个气球,你可以获得 nums[i - 1] * nums[i] * nums[i + 1] 枚硬币。 这里的 i - 1 和 i + 1 代表和 i 相邻的两个气球的序号。如果 i - 1或 i + 1 超出了数组的边界,那么就当它是一个数字为 1 的气球。

求所能获得硬币的最大数量。

示例 1:
输入:nums = [3,1,5,8]
输出:167
解释:
nums = [3,1,5,8] --> [3,5,8] --> [3,8] --> [8] --> []
c o i n s = 3 ∗ 1 ∗ 5 + 3 ∗ 5 ∗ 8 + 1 ∗ 3 ∗ 8 + 1 ∗ 8 ∗ 1 = 167 coins = 3*1*5 + 3*5*8 + 1*3*8 + 1*8*1 = 167 coins=315+358+138+181=167

示例 2:
输入:nums = [1,5]
输出:10

提示:

n == nums.length
1 <= n <= 300
0 <= nums[i] <= 100

主要思路参考题解:https://leetcode.cn/problems/burst-balloons/solutions/337630/zhe-ge-cai-pu-zi-ji-zai-jia-ye-neng-zuo-guan-jian-/

如果数组超出边界就是1,我们将数组两边默认添加1来处理得到nums_insert。

进一步的,我们利用一个二维动态规划,区间长度从小到大进行状态转移。

具体的状态转移方程为:

v a l ( b e g i n , e n d ) = m a x ( v a l ( b e g i n , j ) + n u m s _ i n s e r t [ b e g i n ] ∗ n u m s _ i n s e r t [ j ] ∗ n u m s [ e n d ] + v a l ( j , e n d ) ) val(begin,end)=max(val(begin,j)+nums\_insert[begin]*nums\_insert[j]*nums[end]+val(j,end)) val(begin,end)=max(val(begin,j)+nums_insert[begin]nums_insert[j]nums[end]+val(j,end))

val(begin,j)表示一个开区间(begin,j)范围内可以获得的最大分数。

其中, j ∈ [ b e g i n + 1 , e n d − 1 ] j\in[begin+1,end-1] j[begin+1,end1].

#include<vector>
#include<iostream>

using namespace std;

class Solution {
public:
    int maxCoins(vector<int>& nums) {
        vector<int> nums_insert(nums.size() + 2);
        nums_insert[0] = 1;
        nums_insert[nums.size() + 1] = 1;
        for (int i = 1; i < nums.size() + 1; i++) {
            nums_insert[i] = nums[i - 1];
        }

        vector<vector<int>> dp(nums.size() + 2, vector<int>(nums.size() + 2, 0));
        for (int len = 1; len < nums_insert.size() - 1; len++) {
            for (int i = 0; i + len + 1 < nums_insert.size(); i++) {
                int begin = i;
                int end = i + len + 1;
                for (int j = begin + 1; j < end; j++) { // j作为最后一个扎破的气球
                    int cur = dp[begin][j] + dp[j][end] +
                        nums_insert[begin] * nums_insert[j] * nums_insert[end];
                    if (cur > dp[begin][end]) {
                        dp[begin][end] = cur;
                    }
                }
            }
        }

        return dp[0][nums.size() + 1];
    }
};

int main() {
    vector<int> vec = { 3,1,5,8 };
    Solution sol;
    int res = sol.maxCoins(vec);
    cout << res << endl;
}
  • 31
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cherries Man

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值