如何解决面试问题:投资股票的最大利润
假设我们有 M 个硬币,我们想将其投资于股票。有 N 只股票,他可以投资一些非负整数。股票的利润 i 由二次函数给出:
AiXi2 + BiXi
其中 Xi 是投资于股票 i 的整数金额。 (−1000 ≤ Ai ≤ −1) & (1 ≤ Bi ≤ 1000)
设计一个贪心算法来找出我们可以赚到的最大金额?
不允许将零头资金投资于股票。我们可以投资不到 M 个币。
解决方法
贪心算法确实在这种情况下提供了最佳解决方案。
关键是,如果对于给定的股票,已经投资了 x
个硬币,那么下一次花费的预期收益等于:
next_gain = f(x+1) - f(x) = 2ax + a + b
由于 a
为负,此收益始终随 x
(已投资的硬币数量)而减少。学究,增益函数是凹的。
那么很容易证明最优解是通过一个一个地花费硬币,寻找最大next_gain
的股票。这可以通过 max_heap
实现,从而导致复杂性 O(M logN)
。
如果 M
非常大,则应预见其他解决方案,例如基于拉格朗日函数。在这种情况下将涉及更多的数学。正如您提到的,您正在寻找一种贪婪的解决方案,我认为这个贪婪的解决方案足够快。
这是 C++ 中的代码。应该很容易转换为任何具有最大堆的代码。
输出:
Profit = 16
#include <iostream>
#include <vector>
#include <queue>
struct Stock {
int index;
int n_bought;
int next_gain;
Stock (int i,int n,int gain) : index(i),n_bought(n),next_gain (gain) {};
friend operator< (const Stock& x,const Stock& y) {return x.next_gain < y.next_gain;};
};
long long int profit (std::vector<int>& A,std::vector<int>& B,int M) {
int n = A.size();
if (n != B.size()) exit (1);
std::priority_queue<Stock> candidates;
for (int i = 0; i < n; ++i) {
int gain = A[i] + B[i];
if (gain > 0) candidates.emplace(Stock(i,gain));
}
long long int sum = 0.0;
int coins = 0;
while ((coins < M) &&(!candidates.empty())) {
auto zebest = candidates.top();
candidates.pop();
coins++;
sum += zebest.next_gain;
zebest.n_bought++;
int i = zebest.index;
int gain = 2*A[i]*zebest.n_bought + A[i] + B[i];
if (gain > 0) {
zebest.next_gain = gain;
candidates.push (zebest);
}
}
return sum;
}
int main() {
std::vector<int> A = {-2,-1,-2};
std::vector<int> B = {3,5,10};
int M = 3;
auto ans = profit (A,B,M);
std::cout << "Profit = " << ans << std::endl;
return 0;
}
,
给定函数 Y = AiXi2 + BiXi 是二次函数。
对于约束条件,(-1000 ≤ Ai ≤ -1) 和 (1 ≤ Bi ≤ 1000) 投资可以表示为抛物线,
注意三件事:
- 这些抛物线的最大值由 X'i = -Bi / 2Ai 给定
- 我们应该总是投资硬币 Xi 使得 0 ≤ Xi ≤ X'i 以产生利润。
- 对于给定数量的代币 k,最好将它们投资于具有较大最大值的投资。
贪心算法是,
- 迭代所有 N 个投资,对于每一个我发现它是对应的 Xi = floor(X'i).
- 贪婪地进行所有这样的 k 项投资(首先投资最大 Xi)使得 Sum(Xi) ≤ M 所有这是我拍的。
这是帮助您入门的伪代码,
FIND_MAX(A,N,M):
allProfits = [[]]
for i = 1 to N:
profit = []
X = floor((-B[i]) / (2 * A[i]))
profit.coins = X
profit.index = i
allProfits[i] = profit
Sort(allProfits)
maxProfit = 0
for j = N downto 1:
if(M <= 0):
break
coins = min(allProfits[j].coins,M)
i = allProfits[j].index
maxProfit += (A[i] * coins * coins) + (B[i] * coins)
M -= coins
return maxProfit
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。