冉宝的leetcode笔记--每日一题 8月1日

本文详细记录了冉宝在LeetCode上进行的动态规划题目练习,包括打家劫舍系列、删除并获得点数、跳跃游戏等,探讨了动态规划的解题思路和优化方法,如动态规划数组、前缀和、单调队列等。通过每天的学习和练习,不断提升编程技能和深度学习知识。
摘要由CSDN通过智能技术生成

知道好多人都写了一千+的leetcode才去面试字节,自己确实还有很多需要进步的地方,每天做五题,然后学习2h深度学习,持续进步,加油。

8月1日 – 动态规划

题目198:打家劫舍

链接:https://leetcode-cn.com/problems/house-robber/
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

示例 1:

输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。

示例 2:

输入:[2,7,9,3,1]
输出:12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
     偷窃到的最高金额 = 2 + 9 + 1 = 12 。

提示:

1 <= nums.length <= 100
0 <= nums[i] <= 400

自己的解题思路:
请添加图片描述
代码:

class Solution:
    def rob(self, nums: List[int]) -> int:
        if len(nums) <=2:
            return max(nums)
        
        dp = [num for num in nums]
        dp[2] = dp[0] + nums[2]
        max_value = max(dp[0:3])
        for i in range(3,len(nums)):
            dp[i] = nums[i] + max(dp[i-2],dp[i-3])
            max_value = max(max_value,dp[i])
        return max_value

ps:官方题解思想:
分情况讨论:
dp[i] 偷到第i家时可以获得最大金额。

  • 偷第i家,最大金额为dp[i-2]+nums[i]
  • 不偷第i家,最大金额为dp[i-1]
    更新方程: dp[i] = max(dp[i-2]+nums[i],dp[i-1])
    因为滚动数组,可以只用两个数。

题目213:打家劫舍||

你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。

给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。

示例 1:

输入:nums = [2,3,2]
输出:3
解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。

示例 2:

输入:nums = [1,2,3,1]
输出:4
解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。

思路: 题目的唯一区别就在于需要记住一个状态,不能首尾同时偷。所以可以有两条链路,

  • 第一条:偷了第一家,就可以一直偷到倒数第二家,可以认为和题目198一样,只是最后少了一个房子
  • 第二条:没偷第一家,那就可以一直偷到最后一家,可以认为和题目198一样,只是最开始少了一个房子
    返回更大的一个。
    边界:房子数量<=3 ,直接返回最大的一个。
    需要注意初始化的时候也需要用到max
    请添加图片描述

– 借用上一题官方题解的思想。用滚动数组+ 到第i家可以偷到的最大的金额。

740. 删除并获得点数

https://leetcode-cn.com/problems/delete-and-earn/

给你一个整数数组nums,你可以对它进行一些操作。

每次操作中,选择任意一个nums[i],删除它并获得 nums[i]的点数。之后,你必须删除 所有 等于nums[i] - 1nums[i] + 1的元素。

开始你拥有 0 个点数。返回你能通过这些操作获得的最大点数。

示例 1:

输入:nums = [3,4,2]
输出:6
解释:
删除 4 获得 4 个点数,因此 3 也被删除。
之后,删除 2 获得 2 个点数。总共获得 6 个点数。

示例 2:

输入:nums = [2,2,3,3,3,4]
输出:9
解释:
删除 3 获得 3 个点数,接着要删除两个 2 和 4 。
之后,再次删除 3 获得 3 个点数,再次删除 3 获得 3 个点数。
总共获得 9 个点数。

思路:
初始想法:首先可以看作一个集合题 但是不对,观察示例2,就知道一个数字可以使用多次。
因为数字范围很固定:1 <= nums[i] <= 1 0 4 10^4 104
不妨构思成,这是一个已经排过序的数组第i个元素为[数字i,数字i的数量]

动态规划数组dp[i]可以构思为:选择数字i可以获得的点数。
因为选择数字i,意味着数字i-1没选。即

– 继续思考,这道题和小偷很像,删除 所有 等于 nums[i] - 1 和 nums[i] + 1 的元素。,就相当于我偷了nums[i]的财富,就不能拥有nums[i] - 1 和 nums[i] + 1的财富。

其中 nums[i]的财富为 nums[I] * 数量。

– 这道题的难点可能在于用什么数据结构比较合适。

我自己的思路: hash + 有序数组
hash记录数字数量num_dict,有序数组sorted_nums用于快速迭代。

新数字new_num,索引为ind出来的更新模式
if sorted_nums[ind-1] == new_num - 1:
dp[ind] = max(dp[ind - 2]+ new_numnum_dict[new_num],dp[ind - 1])
else:
dp[ind] = dp[ind - 1] + new_num
num_dict[new_num]

边界:
num_dict之后:
sorted_nums:
只有一个数字的之后,return num_dict[num]*num
只有两个数字 return max(num_dict[num]*num) - 初始化的细节需要注意
请添加图片描述

from collections import Counter
class Solution:
    def deleteAndEarn(self, nums: List[int]) -> int:
        num_dict = Counter(nums)
        sorted_nums = sorted(list(num_dict.keys()))
        if len(sorted_nums) == 1: 
            num = sorted_nums[0] 
            return num_dict[num]*num 
        
        dp = [num_dict[num]*num for num in sorted_nums]
        # 两种情况
        if sorted_nums[1]==(sorted_nums[0]+1):
            dp[1] = max(dp[0],dp[1])
        else:
            dp[1] = dp[0]+dp[1]

        last_value = sorted_nums[1]
        for ind,new_num in enumerate(sorted_nums[2:],start=2):
            if last_value == (new_num-1):
                if dp[ind-2]+new_num*num_dict[new_num] > dp[ind-1]:
                    dp[ind] = dp[ind-2]+new_num*num_dict[new_num]
                    last_value = new_num
                else:
                    dp[ind] = dp[ind-1]
            else:
                dp[ind] = dp[ind-1]+new_num*num_dict[new_num]
                last_value 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值