【动态规划刷题 6】 删除并获得点数&& 粉刷房子

简介: 【动态规划刷题 6】 删除并获得点数&& 粉刷房子

740. 删除并获得点数

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

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

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


链接: 740. 删除并获得点数

示例 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 个点数。


解法思路


从题目可以看出,本题和之前的 打家劫舍 系列题目有些类似,选取 i 后

i-1 和 i+1 都是不能选择的,但是该题我们无法直接进行动态规划,需要对数据进行预处理。


因此,我们可以创建⼀个⼤⼩为 10001 (根据题⽬的数据范围)的 arr 数组,将 nums 数组中每⼀个元素 x ,累加到 arr 数组下标为 x 的位置处,然后在 arr 数组上来⼀次「打家劫舍」即可。


代码:

   int deleteAndEarn(vector<int>& nums) {
        int N=10001;
        //预处理部分
        vector<int> arr(N);
        for(auto e:nums)
        {
            arr[e]+=e;
        }
        //动态规划解题部分
        vector<int> f(N),g(N);
        f[0]=arr[0];f[1]=arr[1];
        g[0]=0;g[1]=arr[0];
        for(int i=2;i<N;i++)
        {
            f[i]=g[i-1]+arr[i];
            g[i]=max(f[i-1],g[i-1]);
        }
        return max(f[N-1],g[N-1]);
    }

LCR 091. 粉刷房子

假如有一排房子,共 n 个,每个房子可以被粉刷成红色、蓝色或者绿色这三种颜色中的一种,你需要粉刷所有的房子并且使其相邻的两个房子颜色不能相同。


当然,因为市场上不同颜色油漆的价格不同,所以房子粉刷成不同颜色的花费成本也是不同的。每个房子粉刷成不同颜色的花费是以一个 n x 3 的正整数矩阵 costs 来表示的。


例如,costs[0][0] 表示第 0 号房子粉刷成红色的成本花费;costs[1][2] 表示第 1 号房子粉刷成绿色的花费,以此类推。


请计算出粉刷完所有房子最少的花费成本。


链接: LCR 091. 粉刷房子


示例 1:

输入: costs = [[17,2,17],[16,16,5],[14,3,19]]

输出: 10

解释: 将 0 号房子粉刷成蓝色,1 号房子粉刷成绿色,2 号房子粉刷成蓝色。

最少花费: 2 + 5 + 3 = 10。


示例 2:

输入: costs = [[7,6,2]]

输出: 2


1.状态表示


对于这种「路径类」的问题,我们的状态表⽰⼀般有两种形式:

  1. i. 从 [i, j] 位置出发,……;
  2. ii. 从起始位置出发,到达 [i, j] 位置,……;

这⾥我们选择⽐较常⽤的⽅式,以某个位置为结尾,结合题⽬要求,定义⼀个状态表⽰:

可以看出,以某个位置为结尾时,结尾处会有三种状态,分别对应着三种颜色,

所以我们定义一个二维数组:

  1. dp[i][0] 表⽰:粉刷到 i 位置的时候,最后⼀个位置粉刷上「红⾊」,此时的最⼩花费;
  2. dp[i][1] 表⽰:粉刷到 i 位置的时候,最后⼀个位置粉刷上「蓝⾊」,此时的最⼩花 费;
  3. ▪ dp[i][2] 表⽰:粉刷到 i 位置的时候,最后⼀个位置粉刷上「绿⾊」,此时的最⼩花 费。

2.状对于 dp[i][0] :

如果第i个位置粉刷上「红⾊」,那么 i-1 位置上可以是「蓝⾊」或者「绿⾊」。因此我们需要知道粉刷到i-1位置上的时候,粉刷上「蓝⾊」或者「绿⾊」的最⼩花费,然后加上i位置的花费即可。于是状态转移⽅程为:态转移方程

dp[i][0] = min(dp[i - 1][1], dp[i- 1][2]) + costs[i - 1][0] ;

同理,可以推出

dp[i][1] = min(dp[i - 1][0], dp[i - 1][2]) + costs[i - 1][1] ;
dp[i][2] = min(dp[i - 1][0], dp[i - 1][1]) + costs[i - 1][2]

3. 初始化

由状态转移方程可知,当 i 为0时,i-1不存在于数组下标中,所以需要对三个

位置进行初始化

    dp[0][0]=costs[0][0];
        dp[1][0]=costs[0][1];
        dp[2][0]=costs[0][2];

4. 填表顺序

根据「状态转移⽅程」得「从左往右,三个表⼀起填」。

5. 返回值

根据「状态表⽰」,应该返回最后⼀个位置粉刷上三种颜⾊情况下的最⼩值,因此需要返回:

min(dp[n--1][0], min(dp[n-1][1], dp[n-1][2])) 

代码:

 int minCost(vector<vector<int>>& costs) {
        int n=costs.size();
        vector<vector<int>> dp(3,vector<int>(n));
        dp[0][0]=costs[0][0];
        dp[1][0]=costs[0][1];
        dp[2][0]=costs[0][2];
        for(int i=1;i<n;i++)
        {
            dp[0][i]=min(dp[1][i-1],dp[2][i-1])+costs[i][0];
            dp[1][i]=min(dp[0][i-1],dp[2][i-1])+costs[i][1];
            dp[2][i]=min(dp[1][i-1],dp[0][i-1])+costs[i][2];
        }
        return min(dp[0][n-1],min(dp[1][n-1],dp[2][n-1]));
    }

相关文章
|
4月前
代码随想录Day29 贪心04 LeetCode T860 柠檬水找零 T406 根据身高重建队列 T452 用最少得箭引爆气球
代码随想录Day29 贪心04 LeetCode T860 柠檬水找零 T406 根据身高重建队列 T452 用最少得箭引爆气球
25 0
|
6月前
|
算法 Java
代码随想录算法训练营第三十四天 | LeetCode 860. 柠檬水找零、406. 根据身高重建队列、452. 用最少数量的箭引爆气球
代码随想录算法训练营第三十四天 | LeetCode 860. 柠檬水找零、406. 根据身高重建队列、452. 用最少数量的箭引爆气球
39 0
|
9月前
多状态动态规划之粉刷房子
多状态动态规划之粉刷房子
|
11月前
剑指offer 68. 骰子的点数
剑指offer 68. 骰子的点数
42 0
|
11月前
Leecode 695. 岛屿的最大面积
Leecode 695. 岛屿的最大面积
22 0
|
11月前
|
机器人 Java Python
leetcode每日一题.200:岛屿数量
leetcode每日一题.200:岛屿数量
68 0
(二分)1227. 分巧克力
(二分)1227. 分巧克力
51 0
|
C++
【LeetCode343】剪绳子(动态规划)
(1)确定状态 dp[i]是将正整数i拆成2个及其以上的正整数后,求所有数的乘积值。
112 0
【LeetCode343】剪绳子(动态规划)
代码随想录刷题|LeetCode 860.柠檬水找零 406.根据身高重建队列 452. 用最少数量的箭引爆气球
代码随想录刷题|LeetCode 860.柠檬水找零 406.根据身高重建队列 452. 用最少数量的箭引爆气球
代码随想录刷题|LeetCode 860.柠檬水找零 406.根据身高重建队列 452. 用最少数量的箭引爆气球
|
机器学习/深度学习 算法 Windows
LeetCode 452. 用最少数量的箭引爆气球(贪心算法)
LeetCode 452. 用最少数量的箭引爆气球(贪心算法)
88 0