动态规划,买卖股票的最佳机会,121,122,123,309,188.714,复习用栈和队列的转换

本文详细探讨了多个股票交易问题的动态规划解决方案,包括121, 122, 123, 188和309等题目。核心思想在于状态定义和状态转移方程,强调了DP状态的重要性。同时,文章还回顾了如何使用队列实现栈的功能,指出了在使用queue模块时需要注意的细节问题。" 50751185,5615058,解决Android文本排版混乱问题,"['Android开发', '字符处理', 'UI排版']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值