Leetcode Best Time to Buy and Sell Stock IV

Leetcode Best Time to Buy and Sell Stock IV,本题主要是找出最大值与买卖次数的关系,很快可以求得结果。

卖买次数与k的关系分析
  1. 首先我们知道当次数不限时,只需要在所有上升部分的起点买入,然后在上升部分的终点卖出即可。
  2. 当次数大于上升段数(设为max)时,与1相同。
  3. k < max时,我们需要在这些部分中进行取舍。首先,我们可能会想到只去差值最大的k个段即可,但是想到相临的段可以进行合并,这样由合并带来的损失可能小于抛弃一段带来的损失,因此不能简单的取最大的k个,如:
"[1, 5], [2, 6], [5, 7]", k=2,
如果直接取[1, 5], [2, 6]其和为:8,
但是如果把[2, 6], [5, 7]合并得[2, 7],然后取[1, 5], [2, 7]其和为:9
相关操作如下
  1. 求出给出序列中所有上升段,数组profits,其由pair组成,分别为段的起点和终点。
  2. k ≥ profits.length(),到第6步;若k < profits.length()到第3步。
  3. 找出profits中差值最小的段,记为min_seg,记损失为:min_lost。
  4. 找出profits中,前后合并损失最小的段min_merge_seg,记损损失为:min_merge_lost。
  5. 比较min_lost和min_merge_lost,如果min_lost <= min_merge_lost,在profitsk 移除min_seg;反之,合并min_merge_seg前后元素。转第2步。
  6. 取得当前profits中元素差值合,即为最大k次交易获得的最大利益。

相关代码如下(请用c++14编译):

#include <iostream>
#include <vector>
#include <iterator>
#include <numeric>

using namespace std;
class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        if (prices.size() <= 1 || k < 1) {
            return 0;
        }
        vector<pair<int, int>> profits;
        int lower = prices[0];
        int higher;
        bool flag = false;
        vector<int>::iterator iter;
        // Get all ascend sequence begin and end point.
        for (iter = prices.begin(); iter != prices.end(); ++iter) {
            if (*(iter - 1) > *iter) {
                if (flag) {
                    profits.emplace_back(lower, higher);
                }
                lower = *iter;
                flag = false;
            } else if (*(iter - 1) <= *iter) {
                flag = true;
                higher = *iter;
            }
        }
        if (flag) {
            profits.emplace_back(lower, higher);
        }

        // Make the number of the elements in profits less than k
        while (profits.size() > k) {
            // Remove the least profit one, resort to deleting the minimum
            // element or merge the adjacent elements
            removeLeast(profits);
        }

        // Get the sum of the profit as the result
        return accumulate(begin(profits), end(profits), 0,
                [](int sum, pair<int, int>& profit) {
                    return sum + (profit.second - profit.first);
                });
    }

    /**
     * Compare removing minimum profit element with merging two adjacent
     * elements and get a better strategy
     */
    void removeLeast(vector<pair<int, int>>& profits) {
        // Get the minimum profit one
        auto min_tran = min_element(begin(profits), end(profits),
                [](pair<int, int>& op1, pair<int, int>& op2) {
                    return (op1.second - op1.first) < (op2.second - op2.first);
                });
        // Get the minimum profit
        int min_tran_value = (*min_tran).second - (*min_tran).first;
        vector<pair<int, int>>::iterator min_iter;

        int min_value = min_tran_value;
        int tmp;
        vector<pair<int, int>>::iterator iter;
        // Get the minimum lost by merge the adjancent two elements
        for (iter = begin(profits) + 1; iter != end(profits); ++iter) {
            tmp = getMergeReduce(*(iter - 1), *iter);
            if (tmp < min_value) {
                min_iter = iter;
                min_value = tmp;
            }
        }

        // Compare the simply remove element lost with merge adjacent elements
        // and get the better strategy
        if (min_tran_value <= min_value) {
            profits.erase(min_tran);
        } else {
            (*min_iter).first = (*(min_iter - 1)).first;
            profits.erase(min_iter - 1);
        }
    }

    /**
     * Calculate the lost by merging the adjacent two elements
     */
    int getMergeReduce(pair<int, int>& op1, pair<int, int>& op2) {
        int before = (op1.second - op1.first) + (op2.second - op2.first);
        int after = op2.second - op1.first;
        return before - after;
    }
};

int main(int argc, char* argv[]) {
    Solution so;
    int k;
    cout << "Please input k: ";
    cin >> k;
    cout << "Please input element:\n";
    vector<int> prices;
    copy(istream_iterator<int>(cin), istream_iterator<int>(),
            back_inserter(prices));
    int re = so.maxProfit(k, prices);
    cout << "re: " << re << endl;
    return 0;
}
Test: 
Please input k: 2
Please input element:
1 5 2 6 5 7
re: 9
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值