LeetCode OJ是一个有一些面试算法题的OJ,这次碰到一道令我颇为头疼的题。
https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/
题意:给定一只股票N天的股价,一个人最多做出k次交易,而且只有在卖了之后才能买进。问最多能获取的最大利益。
我一开始往DP方向想,但是没什么思路。后来在讨论区看到了一个解法,看明白之后感觉做法挺机智的。
做法:
找出股价的顶点和谷底点,用一个栈保存点对。对于两个点对[v1,p1] [v2,p2],如果v1<v2且p1<p2:如果1. price[v2]<price[v1],那么更优的取法就是分别取price[p2]-price[v2]和price[p1]-price[v1];
如果2. price[v1]<price[v2],则有两种取法,第一种是取price[p2]-price[v1](等于只做一次交易),另外一种是price[p2]-price[v2]+price[p1]-price[v1]=(price[p2]-price[v1])+(price[p1]-price[v2])(分开两次做交易)
注意,栈里面的点对不会出现price[p1]<price[v2]的情况的(这个结合代码的具体操作可以保证的)
最后,用优先队列取出前K大的区间,是可以保证不会重复区间的。
代码如下:
//源代码地址:<a target=_blank href="https://leetcode.com/discuss/26745/c-solution-with-o-n-klgn-time-using-max-heap-and-stack">https://leetcode.com/discuss/26745/c-solution-with-o-n-klgn-time-using-max-heap-and-stack</a>
class Solution {//leetcode只需写一个类就行了 public: int maxProfit(int k, vector<int> &prices) { int n = (int)prices.size(), ret = 0, v, p = 0; priority_queue<int> profits; stack<pair<int, int> > vp_pairs; while (p < n) { // find next valley/peak pair for (v = p; v < n - 1 && prices[v] >= prices[v+1]; v++); for (p = v + 1; p < n && prices[p] >= prices[p-1]; p++); // save profit of 1 transaction at last v/p pair, if current v is lower than last v while (!vp_pairs.empty() && prices[v] < prices[vp_pairs.top().first]) { profits.push(prices[vp_pairs.top().second-1] - prices[vp_pairs.top().first]); vp_pairs.pop(); } // save profit difference between 1 transaction (last v and current p) and 2 transactions (last v/p + current v/p), // if current v is higher than last v and current p is higher than last p while (!vp_pairs.empty() && prices[p-1] >= prices[vp_pairs.top().second-1]) { profits.push(prices[vp_pairs.top().second-1] - prices[v]); v = vp_pairs.top().first; vp_pairs.pop(); } vp_pairs.push(pair<int, int>(v, p)); } // save profits of the rest v/p pairs while (!vp_pairs.empty()) { profits.push(prices[vp_pairs.top().second-1] - prices[vp_pairs.top().first]); vp_pairs.pop(); } // sum up first k highest profits for (int i = 0; i < k && !profits.empty(); i++) { ret += profits.top(); profits.pop(); } return ret; } };