动态规划-删除并获取点数

题目描述

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

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

示例:

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

解题思路

预处理

  • 找到最大值:首先,遍历nums数组找到其中的最大值n。这是因为我们后续需要构建一个长度为n+1的数组arr来记录每个数字(从1到n)在nums中出现的总次数乘以该数字的值。注意,arr[0]始终为0,因为不存在数字0。

  • 构建arr数组:然后,再次遍历nums数组,对于每个元素nums[i],将其值加到arr[nums[i]]上。这样,arr[k]就表示数字knums中出现的总次数乘以k的值。

动态规划

动态规划的思路与打家劫舍中讲解的相似(动态规划-打家劫舍-CSDN博客)。

  • 定义状态:接下来,定义一个长度为n+1的数组dp,其中dp[i]表示在考虑前i个数字(即数字1到i)时,通过删除操作可以获得的最大点数。注意这里的“前i个数字”是指arr数组中索引为0到i的元素,它们实际上对应了原数组nums中的数字1到i(如果它们存在的话)。

  • 初始化

    • dp[0]初始化为arr[0],即0,因为没有数字可选时无法获得点数。
    • dp[1]初始化为max(arr[0], arr[1]),但实际上由于arr[0]总是0,所以这里就是arr[1],即数字1在nums中出现的总次数乘以1的值(如果存在的话)。
  • 状态转移

    • 对于i > 1的情况,我们需要考虑两种选择:
      • 不选择数字i,那么最大点数就是dp[i-1],即考虑前i-1个数字时的最大点数。
      • 选择数字i,那么由于不能选择相邻的数字,所以最大点数就是dp[i-2] + arr[i],即考虑前i-2个数字时的最大点数加上数字inums中出现的总次数乘以i的值。
    • 因此,dp[i]的值就是这两种选择中的较大者,即dp[i] = max(dp[i-1], dp[i-2] + arr[i])

结果

  • 最后,遍历dp数组找到其中的最大值,即为通过删除操作可以获得的最大点数。
class Solution {
public:
    int deleteAndEarn(vector<int>& nums) {
        int n = 0;
        for (int i = 0; i < nums.size(); i++) {
            n = max(n, nums[i]);
        }
        vector<int> arr(n + 1, 0);
         
        for (int i = 0; i < nums.size(); i++) {
            arr[nums[i]] += nums[i];
        }
        vector<int> dp(n + 1, 0);
       
        for (int i = 0; i <= n; i++) { // 0  0  2  3  4
            if (i == 0) {
                dp[i] = arr[i];

            } else if (i == 1) {
                dp[i] = max(arr[i], arr[i - 1]);

            } else {
                dp[i] = max(dp[i - 1], dp[i - 2] + arr[i]);
            }
        }
        int ret = 0;
        for (int i = 0; i <= n; i++) {
            ret = max(ret, dp[i]);
        }
        return ret;
    }
};

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CLine类的设计如下: ```c++ class CLine { private: int pointCount; // 组成线的点数 int* pointCoords; // 点坐标数组 int color; // 线的颜色 int width; // 线的宽度 public: // 构造函数 CLine(int count, int* coords, int c, int w) { pointCount = count; pointCoords = new int[count * 2]; for (int i = 0; i < count * 2; i++) { pointCoords[i] = coords[i]; } color = c; width = w; } // 设置颜色 void setColor(int c) { color = c; } // 获取颜色 int getColor() { return color; } // 设置线宽 void setWidth(int w) { width = w; } // 获取线宽 int getWidth() { return width; } // 获取点数 int getPointCount() { return pointCount; } // 添加点 void addPoint(int x, int y) { int* newCoords = new int[(pointCount + 1) * 2]; for (int i = 0; i < pointCount * 2; i++) { newCoords[i] = pointCoords[i]; } newCoords[pointCount * 2] = x; newCoords[pointCount * 2 + 1] = y; delete[] pointCoords; pointCoords = newCoords; pointCount++; } // 删除点 void removePoint(int index) { if (index < 0 || index >= pointCount) { return; } int* newCoords = new int[(pointCount - 1) * 2]; for (int i = 0; i < index * 2; i++) { newCoords[i] = pointCoords[i]; } for (int i = index * 2 + 2; i < pointCount * 2; i++) { newCoords[i - 2] = pointCoords[i]; } delete[] pointCoords; pointCoords = newCoords; pointCount--; } // 修改点坐标 void setPointCoords(int index, int x, int y) { if (index < 0 || index >= pointCount) { return; } pointCoords[index * 2] = x; pointCoords[index * 2 + 1] = y; } // 获取点坐标 void getPointCoords(int index, int& x, int& y) { if (index < 0 || index >= pointCount) { return; } x = pointCoords[index * 2]; y = pointCoords[index * 2 + 1]; } }; ``` 使用示例: ```c++ int coords[] = {0, 0, 100, 100, 200, 200}; CLine line(3, coords, 0xFF0000, 2); line.setColor(0x00FF00); line.setWidth(4); line.addPoint(300, 300); line.removePoint(1); line.setPointCoords(1, 150, 150); int x, y; line.getPointCoords(1, x, y); ``` 这段代码定义了一个CLine类,包含了组成线的点数、点坐标数组、线的颜色、线的宽度等属性,以及设置和获取颜色、线宽,获取线上的点数,添加点到线上,在线上删除点,修改点坐标、获取点坐标等函数。使用示例中创建了一个包含3个点的线,设置了颜色和宽度,添加了一个点,删除了第2个点,修改了第2个点的坐标,获取了第2个点的坐标。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值