樸素的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;
}
};