首页 > 编程语言 >代码随想录算法训练营day39 day40| 198.打家劫舍 213.打家劫舍II 337.打家劫舍III 121. 买卖股票的最佳时机 122.买卖股票的最佳时机II 123.买

代码随想录算法训练营day39 day40| 198.打家劫舍 213.打家劫舍II 337.打家劫舍III 121. 买卖股票的最佳时机 122.买卖股票的最佳时机II 123.买

时间:2024-11-08 19:30:45浏览次数:1  
标签:return nums max self II 最佳时机 prices 打家劫舍 dp

学习资料:https://programmercarl.com/0198.打家劫舍.html#算法公开课

动态规划的打家劫舍系列和股票买卖系列(股票还有贪心算法可解)

学习记录:
198.打家劫舍(一维dp数组,前n间房子都可偷的情况下的最高金额,每间房子偷数都是由前一间和前两间决定)

点击查看代码
class Solution(object):
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        # 先考虑特殊情况
        if len(nums) == 0:
            return 0
        if len(nums) == 1:
            return nums[0]

        # 动态规划之打家劫舍
        # dp[i]代表当考虑从第一间房子到第i间房子都可以偷的时候的最高金额,不一定偷第i间
        dp = [0]*len(nums)
        # 初始化,若只考虑i=0则必须偷第一间
        dp[0]=nums[0]
        # 如果i=1,则选择性地偷第一或第二间,反正金额要最大
        dp[1] = max(nums[0], nums[1])
        # 从第三间房间开始遍历
        for i in range(2, len(nums)):
            # 递推,动态转移方程,要么偷第i间和第i-2间,要么偷第i-1间
            dp[i] = max(dp[i-2]+nums[i], dp[i-1])
        return dp[-1]

213.打家劫舍2(把环形分割为3类情况)

点击查看代码
class Solution(object):
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        # 先考虑特殊情况,没有房子或者只有一栋房子
        if len(nums) == 0:
            return 0
        if len(nums) == 1:
            return nums[0]
        # 环形排布的破题点:分为三种情况,1有头无尾,2无头无尾,3无头有尾;但是这道题1和3都包括了2所以只考虑1、3
        # 再对这两种情况分别调用非环形房子时的打家劫舍问题解法
        result1 = self.robRange(nums, 0, len(nums)-2)
        result2 = self.robRange(nums, 1, len(nums)-1)
        return max(result1, result2)

    def robRange(self, nums, start, end):
        """还是跟打家劫舍1有点区别,那种头指针为0,尾指针为len(nums)-1,这里对应的start和end"""
        if start == end:
            return nums[start]
        pre_max = nums[start]
        cur_max = max(nums[start], nums[start+1])
        for i in range(start+2, end+1):
            temp = cur_max
            cur_max = max(cur_max, pre_max+nums[i])
            pre_max = temp
        return cur_max
        

337.打家劫舍3(树形DP问题,递归,左右根遍历,由左右子树来判断父节点)

点击查看代码
# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def rob(self, root):
        """
        :type root: Optional[TreeNode]
        :rtype: int
        """
        # 调用递归函数,返回的是偷或者不偷时的最高金额,是一个元组
        dp = self.traversal(root)
        # 返回两种情况的最大值
        return max(dp)
    
    def traversal(self, node):
        """树形dp,二叉树,递归,后序遍历"""
        # 父节点dp=[val0, val1], val0代表不偷该节点的最高金额,val1代表偷该节点(那就不能偷左右子节点)的最大金额
        if not node:
            return (0,0)
        # 左
        left = self.traversal(node.left)
        # 右
        right = self.traversal(node.right)
        # 根
        # 情况1:不偷此父节点,则左右子节点可偷可不偷
        val_0 = max(left[0], left[1])+ max(right[0], right[1])   # 分别考虑偷不偷该子节点获得的金额更大
        # 情况2:偷该父节点,则左右子节点都不偷
        val_1 = node.val + left[0] + right[0]
        return (val_0, val_1)
        

121.买卖股票的最佳时机(二维dp数据,是否持股的两个状态对应的金额)

点击查看代码
class Solution(object):
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        # 动态规划:股票问题
        # dp[i][0]代表第i天是持有股票的状态下的金额,dp[i][1]代表第i天是不持有股票的状态下的金额,但是并不清楚是具体哪天买入卖出
        length = len(prices)
        if length == 0:
            return 0
        dp = [[0]*2 for _ in range(length)]  # 要用二维数组
        # 初始化
        # 第一天的状态要么没买入
        dp[0][1] = 0
        # 要么第一天买入
        dp[0][0] = -prices[0]
        # 开始从前到后遍历
        for i in range(1, length):
            # 递归函数,根据前一天的状态决定
            # 若今天有股票,可能是前一天就有的,也可能前一天没有而今天刚买入
            dp[i][0] = max(dp[i-1][0], -prices[i])  # -prices[i]是因为只能买卖一次,前面总金额为0,此时花掉这么多
            # 若今天没有股票,可能是前一天就没有,或者前一天有而今天刚卖出
            dp[i][1] = max(dp[i-1][1], dp[i-1][0]+prices[i])
        return dp[-1][1]   # 最后的最大价值必然是最后一天已经卖出去的状态才有的
            

        

122.买卖股票的最佳时机2(可多次买卖这支股票,与121的区别在于,当第i天持股且前一天不持股的情况下,前一天总金额可能非0)

点击查看代码
class Solution(object):
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        # dp[i][0]代表第i天是处于持有股票的状态对应的利润,dp[i][1]代表第i天没有股票对应的利润
        length = len(prices)
        # if length == 0:
        #     return 0
        # 构造dp二维数组
        dp = [[0]*2 for _ in range(length)]
        # 初始化
        dp[0][0] = -prices[0]  # 第一天买入股票
        dp[0][1] = 0  # 第一天没有股票
        # 开始遍历
        for i in range(1, length):
            # 第i天没有股票,可能前一天也没有(但是可能前面买卖过,总金额非0), 也可能前1天就有而今天卖了
            dp[i][1] = max(dp[i-1][1], dp[i-1][0]+prices[i])
            # 第i天有股票,可能前一天就有,可能前一天没有今天刚买入(前面可能总金额非0)
            dp[i][0] = max(dp[i-1][0], dp[i-1][1]-prices[i])
        return dp[-1][1]
        

123.买卖股票的最佳时机3(与前两种相比,这里分了5种状态分别考虑,难)

点击查看代码
class Solution(object):
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        # 分为5种状态
        # dp[i][0]:没有操作
        # dp[i][1]:第i天第一次持有股票
        # dp[i][2]:第i天第一次不持有股票,也不一定是第i天卖出的,可能是前几天
        # dp[i][3]:第i天第二次持有股票
        # dp[i][4]:第i天第二次不持有股票
        length = len(prices)
        if length==0:
            return 0
        # 构造5维dp数组
        dp = [[0]*5 for _ in range(length)]
        # 初始化和
        dp[0][1] = -prices[0]
        dp[0][3] = -prices[0]
        # 开始遍历
        for i in range(1, length):
            # 根据5种情况写出5种递归函数,由前一天得到
            dp[i][0] = dp[i-1][0]
            dp[i][1] = max(dp[i-1][1], dp[i-1][0]-prices[i])  # 前一天也第一次持股,或者前一天没有而今天第一次持股
            dp[i][2] = max(dp[i-1][2], dp[i-1][1]+prices[i])
            dp[i][3] = max(dp[i-1][3], dp[i-1][2]-prices[i])
            dp[i][4] = max(dp[i-1][4], dp[i-1][3]+prices[i])
        return dp[-1][4]

PS:比背包好理解,但是还是想不到,多复习
今天天气阴沉沉黑乎乎,啥时候下雨啊
终于赶上进度了,勉勉强强,好饿

标签:return,nums,max,self,II,最佳时机,prices,打家劫舍,dp
From: https://www.cnblogs.com/tristan241001/p/18535773

相关文章

  • 第二届生成式人工智能与信息安全国际学术会议(GAIIS 2025)
    第二届生成式人工智能与信息安全国际学术会议(GAIIS2025) 会议时间与地点:2025年2月21日至23日,中国杭州。会议主题:围绕“生成式人工智能与信息安全”的最新研究,聚焦AI热点和难点问题,深入剖析信息安全核心技术。大会主席:DongXu,UniversityofMissouri-Columbia,USA姚信......
  • Day14买卖股票的最佳时机
    给定一个数组prices,它的第i个元素prices[i]表示一支给定股票第i天的价格。你只能选择某一天买入这只股票,并选择在未来的某一个不同的日子卖出该股票。设计一个算法来计算你所能获取的最大利润。返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润......
  • (算法)零钱兑换II————<动态规划>
    1.题⽬链接:518.零钱兑换II2.题⽬描述: 3.解法(动态规划):算法思路:先将问题「转化」成我们熟悉的题型。i.在⼀些物品中「挑选」⼀些出来,然后在满⾜某个「限定条件」下,解决⼀些问题,⼤概率是背包模型;ii.由于每⼀个物品都是⽆限多个的,因此是⼀个「完全背包」问题。接......
  • 107_api_intro_ai_pii-removal
    个人可识别信息(PII)AI去除API数据接口ai/隐私保护基于AI模型自动去除个人识别信息(PII)个人信息保护/AI模型。1.产品功能基于自有专业模型进行PII自动去除高效处理敏感信息全接口支持HTTPS(TLSv1.0/v1.1/v1.2/v1.3);全面兼容AppleATS;全国多节点C......
  • 代码随想录算法训练营 day37 day38| 卡码网52.完全背包 518. 零钱兑换 II 377.
    学习资料:https://programmercarl.com/背包问题理论基础完全背包.html#算法公开课相比于01背包,完全背包中每个物品都可以无限次的放入组合:先遍历物品,再逆序遍历背包排列:先逆序遍历背包,再遍历物品学习记录卡码网52.携带研究资料(dp[i]代表当重量为i时的最大价值)点击查看代码n......
  • IIC通信协议
    IIC是什么?IIC的中文名是集成电路总线,它是一种串行通信总线。IIC协议用来干什么?IIC是一种通信协议,是为了能让主板,或者嵌入式系统等与其他外设模块进行通信而进行开发的。I2C,两线式串行总线,它是由数据线SDA和时钟SCL构成的串行总线,可以发送和接收数据。在CPU与被控IC之间、IC......
  • 【leetcode】40-best-time-to-buy-and-sell-stock 力扣 121. 买卖股票的最佳时机
    买卖股票系列【leetcode】40-best-time-to-buy-and-sell-stock力扣121.买卖股票的最佳时机【leetcode】41-best-time-to-buy-and-sell-stock-ii力扣122.买卖股票的最佳时机II【leetcode】42-best-time-to-buy-and-sell-stock-iii力扣123.买卖股票的最佳时机III【le......
  • 代码随想录第七天|哈希表part02--454.四数相加II、383. 赎金信、15. 三数之和、18. 四
    资源引用:leetcode题目:454.四数相加Ⅱ(454.四数相加II-力扣(LeetCode))383.赎金信(383.赎金信-力扣(LeetCode))15.三数之和(15.三数之和-力扣(LeetCode))18.四数之和(18.四数之和-力扣(LeetCode))例行碎碎念:今天也追赶上了一些进度,虽然生病感冒,但今天很好的坚持了从早到晚......
  • IIS修改网站虚拟路径,IIS虚拟路径设置方法
    在IIS中修改网站的虚拟路径可以通过以下步骤完成:打开IIS管理器:在Windows服务器上,打开“InternetInformationServices(IIS)Manager”。选择网站:在左侧的“连接”面板中,展开“网站”节点,选择需要修改虚拟路径的网站。添加虚拟目录:右键点击网站,选择“添加虚拟目......
  • 数据类型转换和Ascii表常用的几个数值
    1.数据类型转换:当数据类型不一致时,会发生数据类型转换(1)自动类型转换(隐式):数据范围从较小到较大时,代码不需做特殊处理,自动完成(2)强制类型转换(显式):数据范围从较大到较小时,代码需要特殊处理处理格式:范围小的类型范围小的变量名=(范围较小的类型)范围较大的数据;注意:<1>.强制类......