动态规划之 删除并获得点数 斐波那契型

169 阅读3分钟

leetcode 动态规划之 删除并获得点数

哈喽哈喽,我是你们的金樽清酒,今天啊,我要向大家介绍一题难一点的动态规划问题——删除并获得点数。并且这是属于斐波那契型的。给你们看看我刷的斐波那契型的动态规划问题,几道题刷下去,这类问题也就轻而易举了。

image.png

先看题

给你一个整数数组 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 个点数。

 

提示:

  • 1 <= nums.length <= 2 * 104
  • 1 <= nums[i] <= 104

题目分析

这道题要删除一个数,得到它得点数,连带把相邻的数也删除。注意仔细分析题目哦,例如上面有三个三,三个三是都要删除并获得点数的。而且只有相邻的数字要删除,如删除3后,是数字2和数字4要被删除且不或的点数。诶,是不是拿到这题有点摸不着头脑,这也不像我们一般的动态规划呀,不知道为什么,总感觉大脑很乱。

解题思路----转化为打家劫舍问题

首先我们简单的回顾一下打家劫舍问题。一个小偷打劫一个村子,每个房子都放有不同价值的财宝,但是小偷不能同时偷相邻的房子,会触发警报,诶,然后就用动态规划解决问题。没做过的小伙伴可以先去做一下那一题哦,这一题是打家劫舍的进阶版。那我们怎么把这个问题转化为打家劫舍问题呢?那就是创建一个新数组,以nums的值为下标,将一样的数加起来,那就是打家劫舍的问题啦,新数组的值不就是财富数嘛,而且以数组值为下标,解决了相邻数删除的问题,跟打家劫舍就异曲同工啦。

或许你还是一头雾水,那我给你举个例子nums = [2,2,3,3,3,4] arr=[0,0,4,9,6]

nums=2 新数组下标为2,值为几个nums=2相加,下标0和1在nums里面没有值,所以下标0和1的值是为空的,给它们的值赋上0,那这样就可以变为打家劫舍的问题啦。

题解代码

/**
 * @param {number[]} nums
 * @return {number}
 */
var deleteAndEarn = function(nums) {
     if (nums.length <= 0) return 0
    let nlen = nums.length
    let arr = []//生成一个数组,数组元素作为下表,值为相同元素相加
    for (let i = 0; i < nlen; i++) {
        let value = nums[i]
        if(arr[value])
        {
            arr[value] +=value
        }else
        {
            arr[value]=value//这一步是给它赋初值
        }
    }
    for(let i=0;i<arr.length;i++)
    {
        arr[i]=arr[i]||0
    }//给empty元素填充为0
    const dp= new Array(arr.length+1) 
    //开始打家劫舍问题
    dp[0]=0
    dp[1]=arr[0] 
    for(var i=2;i<=arr.length;i++)
    {
        dp[i]=Math.max(dp[i-1],dp[i-2]+arr[i-1])
    }
    return dp[arr.length]
};