Description
給定每日股票價格陣列
prices,可以多次買賣(但同一時間只能持有一股),求最大利潤。
Example:
Input: prices = [7,1,5,3,6,4] Output: 7(第 2 天買、第 3 天賣 +4,第 4 天買、第 5 天賣 +3)
Intuition#
核心思路:貪心——只要明天比今天貴,今天就買明天就賣。所有上漲段的利潤加起來就是最大利潤。
- 與 LC 121(只能交易一次)不同,這題可以多次交易
- 貪心的正確性:任何一段上漲都可以拆成連續日的小交易累加
- 例如 [1,3,5] 中 1→5 的利潤 4 等於 1→3 (2) + 3→5 (2)
Approaches#
1: DP(狀態機)#
- 概念: 定義兩個狀態——持有股票
hold和不持有cash,每天更新 - 時間複雜度:
O(n)- 遍歷一次 - 空間複雜度:
O(1)- 只用兩個變數
class Solution {
fun maxProfit(prices: IntArray): Int {
var cash = 0 // 不持有股票的最大利潤
var hold = -prices[0] // 持有股票的最大利潤
for (i in 1 until prices.size) {
cash = maxOf(cash, hold + prices[i])
hold = maxOf(hold, cash - prices[i])
}
return cash
}
}⭐2: Greedy(累加所有正差值)#
- 概念: 遍歷價格,只要今天比昨天高,就把差值加入利潤
- 時間複雜度:
O(n)- 一次遍歷 - 空間複雜度:
O(1)- 只用一個累加器
class Solution {
fun maxProfit(prices: IntArray): Int {
var profit = 0
for (i in 1 until prices.size) {
if (prices[i] > prices[i - 1]) {
profit += prices[i] - prices[i - 1]
}
}
return profit
}
}補充:峰谷法
找到每一個谷底買入、峰頂賣出,概念上更接近「實際交易」。
class Solution {
fun maxProfit(prices: IntArray): Int {
var i = 0
var profit = 0
while (i < prices.size - 1) {
// 找谷底
while (i < prices.size - 1 && prices[i] >= prices[i + 1]) i++
val valley = prices[i]
// 找峰頂
while (i < prices.size - 1 && prices[i] <= prices[i + 1]) i++
profit += prices[i] - valley
}
return profit
}
}🔑 Takeaways#
- Pattern: 多次交易的股票問題用貪心最直觀;DP 狀態機是通用解法,可推廣到有冷卻期(LC 309)和手續費(LC 714)
- 關鍵技巧: 「累加正差值」的貪心正確性來自:任何連續上漲段的總利潤等於逐日差值之和