【LeetCode】动态规划 刷题训练(四)

文章目录

  • 面试题 17.16. 按摩师(打家劫舍|)
    • 题目解析
    • 状态转移方程
    • 完整代码
  • 213. 打家劫舍 II
    • 题目解析
    • 状态转移方程
    • 完整代码
  • 740. 删除并获得点数
    • 题目解析
    • 预处理
    • 状态转移方程
    • 完整代码

面试题 17.16. 按摩师(打家劫舍|)

点击查看:按摩师

一个有名的按摩师会收到源源不断的预约请求,每个预约都可以选择接或不接。在每次预约服务之间要有休息时间,因此她不能接受相邻的预约。给定一个预约请求序列,替按摩师找到最优的预约集合(总预约时间最长),返回总的分钟数。

示例 1:
输入: [1,2,3,1]
输出: 4
解释: 选择 1 号预约和 3 号预约,总时长 = 1 + 3 = 4。
示例 2:
输入: [2,7,9,3,1]
输出: 12
解释: 选择 1 号预约、 3 号预约和 5 号预约,总时长 = 2 + 9 + 1 = 12。

题目解析

从第一个数1开始,相邻的数不能够放在一起,所以再次 选择 3
即 1+3 =4
从第二个数2开始,相邻的数不能够放在一起,所以再次 选择 1
即 2+1 =3
所以 4 作为最长预约时长

状态转移方程

在上述分析过程中发现,是从左往右的

dp[i] :表示 选到i位置的时候,此时的最长预约时长

对于i位置有两种情况:

1. 选择i 位置的值,选择用f 表示
f[i]:表示 选择i位置的时候,i位置的值(nums[i]) 必选,此时的最长预约时长

2. 不选 i位置的值,不选用g表示
g[i]:表示 选择i位置的时候,i位置的值(nums[i]) 不选, 此时的最长预约时长

f[i]表示 i位置必定选择,则i-1位置必定不能被选
因为要的是最长预约时长,所以寻找[0,i-1] 区间内的最长预约时长 ,而i-1位置不能够被取到 即g[i-1]
再加上i位置的值 为 [0,i]区间的最长预约时长

状态转移方程 为:
f[i] = g[i-1]+nums[i]

g[i] 表示 i位置必定不选,则i-1位置分为两种情况
第一种情况,i-1位置被选择
因为要的是最长预约时长,所以寻找[0,i-1] 区间内的最长预约时长 ,而i-1位置能够被取到 即f[i-1]
第一种情况下的最长预约时长为 : g[i]=f[i-1]

第二种情况,i-1位置不选
因为要的是最长预约时长,所以寻找[0,i-1] 区间内的最长预约时长 ,而i-1位置不能够被取到 即g[i-1]
第二种情况下的最长预约时长为 : g[i]=g[i-1]

状态转移方程为:
g[i] =max(f[i-1],g[i-1]);

完整代码

class Solution {
public:
    int massage(vector<int>& nums) {
       int n=nums.size();

       //处理边界条件
       if(n==0)
       {
           return 0;
       }
       vector<int>f(n,0);
       vector<int>g(n,0);
       int i=0;

       //为了防止越界问题 g[0]和f[0]都需要提前赋值
       g[0]=0;
       f[0]=nums[0];
       for(i=1;i<n;i++)
       {
          f[i]=g[i-1]+nums[i];
          g[i]=max(f[i-1],g[i-1]);
       }
       //返回 取到最后一个位置和 不取最后一个位置 两者的最大值
       return max(f[n-1],g[n-1]);
    }
};

i从1开始,所以要初始化f[0]和g[0]
f[0]包含nums[0]位置的值,所以为nums第一个元素
g[0]不包含nums[0]位置的值,所以为0

返回值为 到最后一个位置选 和到最后一个位置不选,两者中的最大值

213. 打家劫舍 II

点击查看:打家劫舍 II

你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金

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

题目解析

相当于 打家劫舍| 不同点在于 首尾是相连的

若取第一个节点中的值 2 ,则不能取第三个节点中的值 2 ,因为收尾相连 ,所以此时 能够偷取的金额为2

若 取 第二个节点中的值 3 ,则能够偷取的金额为3
所以 最大偷取金额 为 3

通过分类讨论,将环形问题,转换为两个线性的打家劫舍|

情况一:

若偷取下标为0 的位置,因为首尾相连,所以下标为1的 位置 和 下标为n-1的位置就不能偷取到了
而在[2,n-2]区间内 随便偷取(用动态转移方程)

情况二:

若 不偷取 下标为0的位置,此时[1,n-1]区间内可以随便偷取(用动态转移方程)

取 两种情况下的最大值 即为 最大金额

状态转移方程

该动态转移方程 是用于上述分析的情况1中[2,n-2]区间内 随便偷取 和情况2中[1,n-1]区间内可以随便偷取的 情况

f[i]:表示偷取到i位置时,偷nums[i],此时的最大金额
g[i]:表示偷取到i位置时,不偷nums[i],此时的最大金额

若i位置被偷取到 nums[i]的值,则想要求[0,i]的最大金额,就要先求[0,i-1]的最大金额
而由于相邻位置不能偷取,所以i-1位置不能偷取,即g[i-1]
再加上nums[i]的值 为为 [0,i]区间的最大金额

状态转移方程 为:
f[i]=g[i-1]+nums[i]

若i位置没有被偷取到 nums[i]的值,则i-1位置分为两种情况:

情况一:
若i-1位置的值被偷取,
因为要的是最大金额,所以寻找[0,i-1] 区间内的最长金额 ,而i-1位置能够被取到 即f[i-1]
第一种情况下的最大金额为 : g[i]=f[i-1]

情况二:
若i-1位置的值没有被偷取,
因为要的是最大金额,所以寻找[0,i-1] 区间内的最大金额 ,而i-1位置不能够被取到 即g[i-1]
第二种情况下的最长最大金额为 : g[i]=g[i-1]

状态转移方程 为:
g[i]=max(f[i-1],g[i-1]);

完整代码

class Solution {
public:
    int rob1(vector<int> &nums,int left,int right)
    {
        //区间不存在
        if(left>right)
        {
            return 0;
        }
        int n=nums.size();
        vector<int>f(n,0);
        vector<int>g(n,0);
        int i=0;
        //为了防止越界问题,所以下标left处要提前赋值
        f[left]=nums[left];
        g[left]=0;
        for(i=left;i<=right;i++)
        {
            f[i]=g[i-1]+nums[i];
            g[i]=max(f[i-1],g[i-1]);
        }
        //求 取到最后一个位置 和 没有取到最后一个位置 两者的最大值
        return max(f[right],g[right]);
    }
    int rob(vector<int>& nums) {
        int n=nums.size();
        //第一个位置取到值 和 第一个位置没有取到值 的两种情况
       return max(nums[0]+rob1(nums,2,n-2),rob1(nums,1,n-1));
    }
};

n的取值为1到100,若n为1时,n-2为-1,就会导致下标left(1) 小于下标right(2) ,区间不存在

调用rob1,就在区间[left,right]内随便偷取,就相当于打家劫舍|的代码在调用

740. 删除并获得点数

点击查看:删除并获得点数

给你一个整数数组 nums ,你可以对它进行一些操作。
每次操作中,选择任意一个 nums[i] ,删除它并获得 nums[i] 的点数。之后,你必须删除 所有 等于 nums[i] – 1 和 nums[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 个点数。

题目解析

预处理

版权声明:本文为博主作者:风起、风落原创文章,版权归属原作者,如果侵权,请联系我们删除!

原文链接:https://blog.csdn.net/qq_62939852/article/details/131393853

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
扎眼的阳光的头像扎眼的阳光普通用户
上一篇 2024年2月19日
下一篇 2024年2月19日

相关推荐