121:
买卖1次:
思路:记录时时刻刻的最小值,并且记录当前最大的profit,与最大profit进行比较。
因为只能买卖一次,所以买的那天就是负收益,例如-7,-1。 但是卖的那天的价格就是正数。求差值最大。
class Solution:
def maxProfit(self, prices: List[int]) -> int:
min_price = prices[0]
profit = 0
for i in range(len(prices)):
if prices[i] - min_price > profit:
profit = prices[i] - min_price
if prices[i]<min_price:
min_price = prices[i]
return profit
122:
贪心算法,追求短期最大利润:
class Solution:
def maxProfit(self, prices: List[int]) -> int:
profit = 0
for i in range (len(prices)-1):
if prices[i+1]>prices[i]:
profit += prices[i+1] - prices[i]
return profit
123,188
买卖2次或者K次
用三维来递推。
DP状态:i维度表示0到n-1天;j维度表示已买卖了K次,j维度表示持有1股或者没有持有
309是有冻结的时间。将k变量变成1,0,表示可以交易和不能交易的状态
或者允许同时存在X股,那就把j维度变成0到X
123.
class Solution:
def maxProfit(self, prices: List[int]) -> int:
MP = [[[0 for _ in range(len(prices))] for _ in range(3)] for _ in range(2)]
MP[0][0][0], MP[0][0][1] = 0, -prices[0]
for i in range(1,len(prices)):
for k in range (3):
MP[i][k][0] = max(MP[i-1][k][0],MP[i-1][k-1][1]+prices[i])
MP[i][k][1] = max(MP[i-1][k][1],MP[i-1][k-1][0]-prices[i])
return max(MP[n-1][:][0])
问题:
1. 0天不可能有交易1次和交易2次,只需要把他们的profit全部变成负数超小就可以了
2. 交易2次的时候临界条件不可能有MP[i][2][1],所以最好具体情况具体分析
正确解法:
class Solution:
def maxProfit(self, prices: List[int]) -> int:
MP = [[[0 for _ in range(2)] for _ in range(3)] for _ in range(len(prices))]
MP[0][0][0], MP[0][0][1] = 0, -prices[0]
MP[0][1][0], MP[0][1][1] = -sys.maxsize, -sys.maxsize #不合法,赋值为最小
MP[0][2][0] = -sys.maxsize #不合法,赋值为最小
for i in range(1,len(prices)):
MP[i][0][0] = MP[i-1][0][0]
MP[i][0][1] = max(MP[i-1][0][1],MP[i-1][0][0]-prices[i])
MP[i][1][0] = max(MP[i-1][1][0],MP[i-1][0][1]+prices[i])
MP[i][1][1] = max(MP[i-1][1][1],MP[i-1][1][0]-prices[i])
MP[i][2][0] = max(MP[i-1][2][0],MP[i-1][1][1]+prices[i])
return max(MP[len(prices)-1][0][0],MP[len(prices)-1][1][0],MP[len(prices)-1][2][0])
最牛解法:
5行代码搞定所有股票买卖问题 - 买卖股票的最佳时机 IV - 力扣(LeetCode) (leetcode-cn.com)
随时保证自己手里面的钱最多,利润说话why?
有些地方真的不能细想,很容易把自己绕进去。要稍微宏观一点去想,就是我这一次操作想利益最大,那么我肯定需要在之前操作利益最大的基础上。所以每一次操作只需要看手里的钱,把买看成卖负值,买卖当成有先后顺序的两个状态,而不用分开去考虑
优化后的解法:
121
class Solution:
def maxProfit(self, prices: List[int]) -> int:
buy, sell = -float("inf"),0
for p in prices:
buy = max(buy,0-p)
sell = max(sell,buy+p)
return sell
122
class Solution:
def maxProfit(self, prices: List[int]) -> int:
buy, sell = -float("inf"),0
for p in prices:
buy = max(buy,sell-p)
sell = max(sell,buy+p)
return sell
123
我们只需要考虑买卖的状态,也就是第一次买/卖,第二次买/卖
class Solution:
def maxProfit(self, prices: List[int]) -> int:
b1,b2,s1,s2 = -float("inf"),-float("inf"),0,0
for p in prices:
b1 = max(b1, 0-p)
b2 = max(b2, s1-p)
s1 = max(s1, b1+p)
s2 = max(s2, b2+p)
return s2
188
class Solution:
def maxProfit(self, k: int, prices: List[int]) -> int:
buy = [-float("inf")]*(k+1)
sell = [0]*(k+1)
for p in prices:
for i in range(1,k+1):
buy[i] = max(buy[i],sell[i-1]-p)
sell[i] = max(sell[i],buy[i]+p)
return sell[-1]
309
冷冻期1天,可以进行无数次交易:
相当于用一个pre_sell的状态来延迟这个sell的冷冻期。
每次循环的时候pre_sell会更新,buy只能从pre_sell状态那里买入
第二道题的变形而已
class Solution:
def maxProfit(self, prices: List[int]) -> int:
buy,sell,pre_sell = -float("inf"),0,0
for p in prices:
buy = max(buy,pre_sell-p)
pre_sell,sell = sell,max(sell,buy+p)
return sell
714
class Solution:
def maxProfit(self, prices: List[int], fee: int) -> int:
buy,sell = -float("inf"),0
for p in prices:
buy = max(buy,sell-p-fee)
sell = max(sell,buy+p)
return sell
总结:
DP的状态定义非常的重要!!直接决定了解题的难易程度。
状态定义好了之后再去思考它的状态转移方程
复习:
用队列实现栈:
注意:
import queue as q 要写在init里面
queue的4个函数,q.Queue() q.put(x) q.get() q.qsize() q.empty()
调用函数的时候一定要记得加括号
class MyStack:
def __init__(self):
"""
Initialize your data structure here.
"""
import queue as q
self.q1 = q.Queue()
self.q2 = q.Queue()
def push(self, x: int) -> None:
"""
Push element x onto stack.
"""
self.q1.put(x)
def pop(self) -> int:
"""
Removes the element on top of the stack and returns that element.
"""
while (self.q1.qsize()>1):
self.q2.put(self.q1.get())
ans = self.q1.get()
self.q1, self.q2 = self.q2, self.q1
return ans
def top(self) -> int:
"""
Get the top element.
"""
while (self.q1.qsize()>1):
self.q2.put(self.q1.get())
ans = self.q1.get()
self.q2.put(ans)
self.q1, self.q2 = self.q2, self.q1
return ans
def empty(self) -> bool:
"""
Returns whether the stack is empty.
"""
return self.q1.empty()
# Your MyStack object will be instantiated and called as such:
# obj = MyStack()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.top()
# param_4 = obj.empty()
注意问题:
如果引用queue的话,就不能直接用not 当成列表来判断
这样是错误的,它是一个创建的对象,并不是一个stack
class MyQueue:
def __init__(self):
"""
Initialize your data structure here.
"""
import queue as q
self.q1 = q.LifoQueue()
self.q2 = q.LifoQueue()
def push(self, x: int) -> None:
"""
Push element x to the back of queue.
"""
self.q1.put(x)
def pop(self) -> int:
"""
Removes the element from in front of queue and returns that element.
"""
if self.q2.empty():
while not self.q1.empty():
self.q2.put(self.q1.get())
return self.q2.get()
def peek(self) -> int:
"""
Get the front element.
"""
if self.q2.empty():
while not self.q1.empty():
self.q2.put(self.q1.get())
ans = self.q2.get()
self.q2.put(ans)
return ans
def empty(self) -> bool:
"""
Returns whether the queue is empty.
"""
return self.q1.empty() and self.q2.empty()
# Your MyQueue object will be instantiated and called as such:
# obj = MyQueue()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.peek()
# param_4 = obj.empty()