Leetcode Best Time to Buy and Sell Stock IV(最大子段和)

朴素的O(n^2)过不了,这里借鉴前人的思想,总结一下。

主要利用栈维护对后面产生影响的字段,然后利用贪心的思想逐步合并。

首先,找到每一对最低点(vx),最高点(px);

其次,合并当前(vx, px) 与栈内的点对(top_vx, top_px),分两种情况

1、若top_vx  >= vx,考虑到vx处在更低点,(top_vx, top_px)对后面的点对不会有影响,则对(top_vx, top_px)计算价值并出栈;

2、若top_px <= px(ps:此时top_vx  < vx), 

      a、若最优解只包含两对点的其中一对,显然可以合并两对点为(top_vx, px)最优;

      b、若最优解中包含两对点,则可将两对点转化成(top_vx, px), (vx, top_ px), 其中(vx, top_ px)对后面的点对不会有影响,则对(vx, top_ px)对计算价值并出栈,同时更新(vx, px)->(top_vx, px);

最后,将栈内的点对全部计算价值(显然栈内的点对都不必合并)。

class Solution {
        stack< pair<int, int> > waiting;
        vector<int> profits;
public:
    int maxProfit(int k, vector<int>& pr) {
        int len = pr.size();
        if(len < 2 || k < 1) return 0;
        while(!waiting.empty()) waiting.pop();
        profits.clear();
        
        int posv, posp = -1;
        while(true)
        {
            for(posv = posp + 1; (posv + 1) < len && pr[posv] >= pr[posv + 1]; posv++);
            for(posp = posv + 1; (posp + 1) < len && pr[posp] <= pr[posp + 1]; posp++);
            if(posp >= len) break;
            
            for(; !waiting.empty() && pr[waiting.top().first] >= pr[posv]; waiting.pop())
            {
                profits.push_back(pr[waiting.top().second] - pr[waiting.top().first]);
            }
            for(; !waiting.empty() && pr[waiting.top().second] <= pr[posp]; waiting.pop())
            {
                profits.push_back(pr[waiting.top().second] - pr[posv]);
                posv = waiting.top().first;
            }
            waiting.push(make_pair(posv, posp));
        }
        
        for(; !waiting.empty(); waiting.pop())
        {
            profits.push_back(pr[waiting.top().second] - pr[waiting.top().first]);
        }
        
        int ans = 0;
        if(k >= profits.size()) 
        {
            ans = accumulate(profits.begin(), profits.end(), 0);
        }
        else
        {
            nth_element(profits.begin(), profits.begin() + k - 1, profits.end(), greater<int>());
            ans = accumulate(profits.begin(), profits.begin() + k, 0);
        }
        
        return ans;
    }
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值