算法学习 | day42/60 买股票的最佳时机/买股票的最佳时机

一、题目打卡

        1.1 买股票的最佳时机

        题目链接:. - 力扣(LeetCode)

// class Solution {
// public:
//     int maxProfit(vector<int>& prices) {
//         if(prices.size() <= 1) return 0;
//         int res = 0;
//         for(int i = 0 ; i < prices.size();i++){
//             int max_ = *max_element(prices.begin() + i, prices.end());
//             int min_ = *min_element(prices.begin(), prices.begin() + i);
//             res = max(res, max_ - min_);
//         }
//         return res;
        
//     }
// };

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

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        vector<vector<int>> dp(1, vector<int>(2,0));
        // vector<vector<int>> dp(prices.size(), vector<int>(2,0));
        
        dp[0][0] = -prices[0]; // 持有这一笔股票
        dp[0][1] = 0; // 未持有这一笔股票

        for(int i = 1 ; i < prices.size();i++){
            // dp[i][0] = max(dp[i - 1][1] - prices[i], dp[i - 1][0]);
            // dp[i][0] = max(-prices[i], dp[i - 1][0]); // 因为这里只买一次,所以不存在累加,因而从未持有变成持有的时候,直接就是 -price[i]
            // dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]);
            // int tmp = dp[0][1];
            dp[0][1] = max(dp[0][1], dp[0][0] + prices[i]);
            dp[0][0] = max(dp[0][0], -prices[i]);
        }
        // return max(dp[prices.size() - 1][0], dp[prices.size()-1][1]); 
        return max(dp[0][0], dp[0][1]); 
    }
};

        因为题目要求的是最终只有一次股票的买入和卖出,所以其实最直接的思想就是遍历整个prices,然后从当前节点之前取最小,当前节点之后取最大,然后在遍历的过程中,记录下来两者相减的最大值,也就是最终的结果,但是这样是 n^2 的时间复杂度,因而肯定最终通过不了,这里有一个小的tips我这个方法获得的是迭代器,需要进行取值的操作。

        第二种思路是贪心的方法,其实也就是上面那个方法的优化版,考虑到最小值和最大值的计算,其实没有必要在遍历过程的每一次都进行,最小值其实只用统计一次,后来就不断计算当前值和这个最小值之间的区间就好了,这样其实也就是贪心的思路。

        最后就是动态规划,相较于之前的动态规划,我认为这个重点在于理解动态规划状态的一个定义,对于动态规划而言,状态需要包括所有变化过程的一个动态的变量的描述,这个题目中,动态的遍历就被定义为:是否持有股票和从第一天到第 i 天所得到的最大的利润,而前者其实包含了四个层面的内容,持有股票有可能是当天买的,也有可能是继承的前一天的,未持有股票,有可能是当天卖掉了,也有可能是和前一天未持有一样的状态,这样也就描述清楚了整个动态变化的过程。

        不过这个题目还有一个细节就是,如果只买一次的话,那么状态转移方程里面:持有股票这个状态如果是由前一天未持有股票转移而来,这样的情况下,不能加上前一天未持有的状态变量的值,因为只存在买一次的过程,加上了就是计算的累加,也就是多次购买。

        1.2 买股票的最佳时机II

        题目链接:. - 力扣(LeetCode)

// class Solution {
// public:
//     int maxProfit(vector<int>& prices) {
//         if(prices.size() == 1) return 0;
//         // int result = 0;
//         // int prediff = 0;
//         // int curdiff = 0;
//         // int tmp = 0; // 存储低谷 i 的位置
//         // for(int i = 0, j = 1; j < prices.size();i++,j++){
//         //     curdiff = prices[j] - prices[i];
//         //     if(curdiff > 0 && prediff <=0){
//         //         tmp = i;
//         //     }
//         //     else if(curdiff <= 0 && prediff > 0){
//         //         result += prices[i] - prices[tmp];
//         //     }
//         //     else if(curdiff)
//         //     prediff = curdiff;
//         // }
//         // return result;
//         int result = 0;
//         for(int i = 0; i < prices.size() -1 ; i++){
//             if(prices[i+1] - prices[i] >=0) result+=prices[i+1]-prices[i];
//         }
//         return result;
//     }
// };

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        vector<vector<int>> s(1, vector<int>(2,0));
        s[0][0] = 0;
        s[0][1] = -prices[0]; // 持有股票

        for(int i = 0 ; i < prices.size() ; i++){
            int tmp = s[0][0];
            s[0][0] = max(s[0][1] + prices[i], s[0][0]);
            s[0][1] = max(s[0][1], s[0][0] - prices[i]);
        }
        return max(s[0][1], s[0][0]);
    }
};

        这个就是重复多次购买的情况,在1.1 也分析清楚了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值