真实面经题目 · 原创解析
只能买卖一次时,如何计算股票最大收益?
一次买卖股票最大收益的核心是维护历史最低买入价,并在每一天尝试把当天价格作为卖出价更新最大利润。
出现于:字节跳动 · 算法
真实面经题目 · 原创解析
一次买卖股票最大收益的核心是维护历史最低买入价,并在每一天尝试把当天价格作为卖出价更新最大利润。
只能买卖一次时,本质是在数组中找一对下标 i < j,让 prices[j] - prices[i] 最大。遍历价格时维护到当前为止的最低价格 minPrice,把当前价格减 minPrice 得到如果今天卖出的利润,并更新最大值。然后再用当前价格更新 minPrice。这样一趟扫描就能完成,时间复杂度 O(n),空间 O(1)。面试时要说明不能先卖后买、价格单调下降时利润通常返回 0,以及它和无限次、两次买卖的状态转移不同。
题目限制只能买卖一次,意味着只能选择一个买入点和一个更晚的卖出点。不能把多个上涨区间累加,也不能出现先卖后买的下标顺序错误。
遍历到第 k 天时,最优买入价只能来自前 k 天已经见过的最低价格。用一个变量 minPrice 记录它,就不需要枚举所有买入日。
当前价格 price 减去 minPrice,就是如果今天卖出的最大可能利润。用它更新 maxProfit,再把 minPrice 更新成当前和历史最低的较小值。
算法只扫描一次数组,时间复杂度 O(n),额外空间 O(1)。空数组、单个价格或单调下降时没有正收益,通常返回 0。
无限次买卖可以累加所有正收益,两次买卖需要前后缀或状态机。一次买卖题不要过度设计成多状态 DP,但要能解释这些变体的差异。
function maxProfitOnce(prices) {
let minPrice = Infinity;
let maxProfit = 0;
for (const price of prices) {
maxProfit = Math.max(maxProfit, price - minPrice);
minPrice = Math.min(minPrice, price);
}
return maxProfit;
}
maxProfitOnce([1, 3, 1, 8, 10, 3]); // 9 每次当前价格减历史最低价都不为正,maxProfit 保持 0,表示不交易更优。
只要后一天比前一天高,就累加差值,相当于吃掉所有上涨区间。
可以用四个状态表示第一次买入、第一次卖出、第二次买入、第二次卖出的最优收益,逐日转移。