题目重点:两状态DP保留旧日状态,每次卖出扣费,避免费用重复和未平仓虚增收益。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 非负整数价格与手续费,最多持有一股、不可做空;买后卖为交易,费用每次卖出一次。
- 训练每天最多一动作,允许不交易;最终必须无持仓。冷却期与交易次数上限未给,不默认加入。
解题路线
- cash为处理前缀后无股最高现金,hold为持一股最高账面现金。更新new_cash=max(cash,hold+price-fee),new_hold=max(hold,cash-price),两个均读取旧状态。
- 不交易、卖出、买入覆盖合法一天决策;cash初始0,hold不可达。代码用None避免负无穷浮点与超大整数混算溢出。
- 手续费放卖出或买入可选择一种约定,但不能两边都扣;若放买入,状态初值和解释必须跟着改。最后返回cash,未卖出资产不能直接算已实现收益。
- 只累计正相邻涨幅会在小波动里多次扣费,可能错过一次长持仓更优;两状态DP能比较多次交易与跨下跌保持仓位。
- 如果题目还需要统一不同次数模式,必须先核前两道正式规则,不解码谐音就宣称单次/多次原题已经全部完成。
手动走一遍
训练prices=[1,3,2,8,4,9]、fee=2,1买8卖得5,4买9卖得3,共8。价格不涨或手续费很大时结果0。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
def maximum_profit(prices,fee):
"""At most one share, no shorting; fee once per sell, at most one action per day."""
if fee < 0 or any(p < 0 for p in prices):raise ValueError("nonnegative prices and fee required")
cash=0
hold=None
for price in prices:
new_cash=max(cash,hold+price-fee) if hold is not None else cash
new_hold=max(hold,cash-price) if hold is not None else cash-price
cash,hold=new_cash,new_hold
return cash
复杂度
O(n)时间、O(1)辅助状态;固定宽度需核金额范围,Python大整数的位复杂度另算。
易错点与追问
容易失分的边界
- 每买卖各扣fee造成双扣。
- 返回hold当最终现金。
- 用浮点无穷参与任意大整数加减。
继续深挖
- 有冷却一天时怎样加状态?
- 最多两次交易怎样加次数维?
- 需要输出买卖日怎么回溯?
