題目描述
假設 力扣(LeetCode)即將開始其 IPO。爲了以更高的價格將股票賣給風險投資公司,力扣 希望在 IPO 之前開展一些項目以增加其資本。 由於資源有限,它只能在 IPO 之前完成最多 k 個不同的項目。幫助 力扣 設計完成最多 k 個不同項目後得到最大總資本的方式。
給定若干個項目。對於每個項目 i,它都有一個純利潤 Pi,並且需要最小的資本 Ci 來啓動相應的項目。最初,你有 W 資本。當你完成一個項目時,你將獲得純利潤,且利潤將被添加到你的總資本中。
總而言之,從給定項目中選擇最多 k 個不同項目的列表,以最大化最終資本,並輸出最終可獲得的最多資本。
樣例:
輸入: k=2, W=0, Profits=[1,2,3], Capital=[0,1,1].
輸出: 4
解釋:
由於你的初始資本爲 0,你儘可以從 0 號項目開始。
在完成後,你將獲得 1 的利潤,你的總資本將變爲 1。
此時你可以選擇開始 1 號或 2 號項目。
由於你最多可以選擇兩個項目,所以你需要完成 2 號項目以獲得最大的資本。
因此,輸出最後最大化的資本,爲 0 + 1 + 3 = 4。
解題思路:
1、定義一個結構體,用來表示資本和利潤
2、按照資本大小建立小根堆,即資本數額小的爲堆頂
3、只要當前堆頂的金額比初始金額小或者等於,就彈出堆頂,
4、將彈出的堆頂元素加入大根堆(是按照利潤大小建立,即利潤大的元素在堆頂)。
5、此時,大根堆的堆頂,即爲當前金額所獲最大利潤
6、考慮邊界問題,最多完成K次項目,大根堆爲空,小根堆的堆頂元素大於原始金額W。
注意:
優先隊列和排序的規則剛好相反:
若排序是從小到大排序,則爲大頂堆
若排序是從大到小排序,則爲小頂堆
C++ STL庫中的sort函數是從小到大排序
而priority_queue隊列是按照大頂堆來實現的。
下面爲AC代碼:
//結點
struct capital_node
{
int capital;
int profits;
capital_node(int capital, int profits) {
this->capital = capital;
this->profits = profits;
}
};
//比較策略
struct minCapitalCompare//根據花費金額大小比較
{
bool operator() (const capital_node node1, const capital_node node2) const {//構造小頂堆
return node1.capital > node2.capital;
}
};
struct maxProfitCompare//根據利潤大小比較
{
bool operator() (const capital_node node1, const capital_node node2) const {//構造大頂堆
return node1.profits < node2.profits;
}
};
int findMaximizedCapital(int k, int W, vector<int>& Profits, vector<int>& Capital) {
priority_queue<capital_node, vector<capital_node>, minCapitalCompare> min_capital_queue;//小頂堆
priority_queue<capital_node, vector<capital_node>, maxProfitCompare> max_profits_queue;//大頂堆
for (int i = 0;i < Capital.size();i++)
{
capital_node node(Capital[i], Profits[i]);
min_capital_queue.push(node);
}
for (int i = 0;i < k;i++)
{
while (!min_capital_queue.empty() && min_capital_queue.top().capital <= W)
{
capital_node temp = min_capital_queue.top();
min_capital_queue.pop();
max_profits_queue.push(temp);
}
while (max_profits_queue.empty())//大頂堆中已經沒有元素了
{
return W;
}
capital_node node = max_profits_queue.top();
max_profits_queue.pop();
W += node.profits;
}
return W;
}
第二種寫法:
思想都是一樣的,只是實現的方法不同。
下面是用c++ 的 multimap(按照鍵值來從小到大排序)實現的,則可以當作小頂堆來看待。而priority_queue內部是按照大根堆的來實現的。故可以不用寫比較策略
下面爲AC代碼:
int findMaximizedCapital(int k, int W, vector<int>& Profits, vector<int>& Capital) {
multimap<int, int> m;//第一個參數表示 capital 第二個參數表示 profits
for (int i = 0;i < Capital.size();i++)
{
m.insert(pair<int, int>(Capital[i], Profits[i]));//map 根據鍵值來從大到小排序
}
priority_queue<int> p_queue;//表示利潤的優先隊列,默認是大頂堆
for (int i = 0;i < k;i++)
{
for (multimap<int, int>::iterator it = m.begin(); it != m.end(); it++)//遍歷小頂堆
{
if ((*it).first <= W)//表示當前花費沒有超過初始金額
{
p_queue.push((*it).second);
m.erase(it);
}
else
{
break;
}
}
if (p_queue.empty())//金額優先隊列爲空,即大頂堆爲空
{
break;
}
int profit = p_queue.top();
p_queue.pop();
W += profit;//現在的初始金額
}
return W;
}