Leetcode Best Time to Buy and Sell Stock IV,本题主要是找出最大值与买卖次数的关系,很快可以求得结果。
卖买次数与k的关系分析
- 首先我们知道当次数不限时,只需要在所有上升部分的起点买入,然后在上升部分的终点卖出即可。
- 当次数大于上升段数
(设为max)
时,与1
相同。 - 当
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。
相关操作如下
- 求出给出序列中所有上升段,数组
profits
,其由pair
组成,分别为段的起点和终点。 - 若
k ≥ profits.length()
,到第6步;若k < profits.length()
到第3步。 - 找出profits中差值最小的段,记为min_seg,记损失为:min_lost。
- 找出profits中,前后合并损失最小的段min_merge_seg,记损损失为:min_merge_lost。
- 比较min_lost和min_merge_lost,如果min_lost <= min_merge_lost,在profitsk 移除min_seg;反之,合并min_merge_seg前后元素。转第2步。
- 取得当前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