中秋快乐&&股市飘红--- Best Time to Buy and Sell Stock III&& II&&I

题目大意

     给定一个数组a,a[i]表示第i天的股票价格,求:

     I.若只交易一次,获利最大值。

II.若交易任意次,获利最大值。

III.若最多交易两次,获利最大值。

解题思路

     前两天刷了I和II,然后正好碰上中秋佳节,在家爽了两天后回来又把III给过了,又正好赶上股票大涨,这题还真是应景,在此抓住中秋的尾巴祝各位中秋快乐。废话少说,开始撸题。(我发现撸这个字颇有深意,完全可以取代搞这个神级词汇(0-0)!)。。。

I、若只允许交易一次,显然只要低买高卖、投机倒把就行了,但是单从题目给定的数据来看无法准确获取到最大的落差,因此这里卡了一小会儿,但是在我吃完中饭集满查克拉之后,我突然发现可以处理一下原来的数组,将其相邻数值相减可以直接得到每相邻交易的成本差值,这样就能得到一个n-1的数组,就是每次交易(相邻两天的交易,即第一天买后一天卖)的获利(可能为负数),然后就简单了,只要求一次最大连续和就能得到题目的解。是不是很简单?

II、看懂了I,II就比较简单了,显然我只要保证每次都获利那就肯定是最大值了,基本的贪心思路,因此只要将所有获利为正数的求和就能得到解。

III、这题应该是这个股票系列里面最难的一道了,只允许最多交易两次,这个最多很是奇怪,所以纠结了一小会儿,最初想到是不是前两个最大的获利连续和,但是怎么都没有想出来如何求得这两个最大的获利连续和(因为两个连续和序列之间不能相交,而且可能出现相同的情况,因此编码并不是十分容易),后来想着牺牲一点时间来实现,对每一个点考虑为截断点,然后前后各求一次最大连续和,这样时间复杂度为O(n^2),结果TLE。。FUCK!!。。没办法,想想能不能压缩复杂度,显然这个计算有太多的重复运算了,我每次都得重新计算已经计算过的连续最大和,那么为何不使用两个数组分别记录第i个截断点前,后的最大连续和呢?果然这样一处理就变成了O(n)的复杂度,成功解决了。

总结

      先得大略,逐步求精

代码

I:

class Solution {
public:
    int maxProfit(vector<int> &prices) 
    {
        int n = prices.size();
        int profit = INT_MIN;
        int sum = 0;
        for (int i = 1 ; i < n; i ++){
            prices[i-1] = prices[i]-prices[i-1];
        }
        for (int i = 0 ; i < n-1; i ++){
            sum += prices[i];
            profit = max(profit, sum);       
            if (sum < 0)sum = 0;
        }
        return profit < 0?0:profit;
    }
};

II:

class Solution {
public:
    int maxProfit(vector<int> &prices) 
    {
        int n = prices.size();
        int profit = 0;
        int sum = 0;
        for (int i = 1 ; i < n; i ++){
            prices[i-1] = prices[i]-prices[i-1];
        }
        int temp = INT_MIN;
        for (int i = 0 ; i < n-1; i ++){
            if (prices[i] > 0)  profit += prices[i];
        }
        return profit < 0?0:profit;
    }
};

III:

class Solution {
public:
    int maxProfit(vector<int> &prices) 
    {
        int n = prices.size();
        int profit1 = INT_MIN, profit2 = INT_MIN;
        int before[100010], after[100010];
        memset(before,0,sizeof(before));
        memset(after,0,sizeof(after));
        int sum1 = 0, sum2 = 0;
        for (int i = 1 ; i < n; i ++){
            prices[i-1] = prices[i]-prices[i-1];
        }
        for (int i = 0 ; i < n-1; i ++){
            sum1 += prices[i];
            sum2 += prices[n-2-i];
            profit1 = max(profit1, sum1);
            profit2 = max(profit2, sum2);
            before[i] = profit1;
            after[n-2-i] = profit2;
            if (sum1 < 0)sum1 = 0;
            if (sum2 < 0)sum2 = 0;
        }
        int ans = INT_MIN;
        for (int i = 0; i < n-1; i ++){
            if (i != n-2 && i != 0)  ans = max(ans, before[i]+after[i+1]);
            if (i == 0) ans = max(ans, after[i]);
            if (i == n-2) ans = max(ans,before[i]);
            
        }
        return ans < 0?0:ans;
    }
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值