算法题目--Delete and Earn

题目来源:

点击这里

题目描述:

Given an array nums of integers, you can perform operations on the array.
In each operation, you pick any nums[i] and delete it to earn nums[i] points. After, you must delete every element equal to nums[i] - 1 or nums[i] + 1.
You start with 0 points. Return the maximum number of points you can earn by applying such operations.

Example 1:

Input: nums = [3, 4, 2] Output: 6 Explanation: Delete 4 to earn 4
points, consequently 3 is also deleted. Then, delete 2 to earn 2
points. 6 total points are earned.

Example 2:

Input: nums = [2, 2, 3, 3, 3, 4] Output: 9 Explanation: Delete 3 to
earn 3 points, deleting both 2’s and the 4. Then, delete 3 again to
earn 3 points, and 3 again to earn 3 points. 9 total points are
earned.

Note:

The length of nums is at most 20000.
Each element nums[i] is an integer in the range [1, 10000].

心路历程:

这道题是leetcode上面位于动态规划目录下的一道题,难度为Medium。刚开始看到这道题的时候,没什么思路,找不到很好的子问题。所以写了一个遍历并递归的算法,输入测试用例倒没什么问题,但是提交后运行只通过了10个测试样例,后面的全部超时。如下图:
错误答案
于是看了答案,确实有一种醍醐灌顶的感觉。先把所有的数从小到大排个序(因为数的范围有限,所以可以使用桶排序)。这样,问题就变成从左往右依次考虑是否加入某个数。过程中使用use和avoid两个变量来分别记录加入和不加入当前数所得到的值。接着考虑下一个数,若与前一个数不连续。可以直接加入;若与前一个数连续,就要加上前一个数的avoid值。这里有一点要注意,每个数都有可能重复,但是它们要不全部加入,要么全部不加,这是因为当加入第一个这种数时,它的左右邻都会被删除,所以其它的相同的数没办法再被删除(因为没有邻居了)。leetcode上给了Java和Python的解法,下面给出了类似的C++解法。

解决方案:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Solution {
public:
    int deleteAndEarn(vector<int>& nums) {
        int count[10001] = { 0 };
        for (int i = 0; i < nums.size(); i++) count[nums[i]]++;
        int avoid = 0;
        int use = 0;
        int prev = -1;
        for (int k = 0; k <= 10000; ++k) {
            if (count[k] > 0) {
                int m = max(avoid, use);
                if (k - 1 != prev) {
                    use = k * count[k] + m;
                    avoid = m;
                }
                else {
                    use = k * count[k] + avoid;
                    avoid = m;
                }
                prev = k;
            }
        }
        return max(avoid, use);
    }
};
int main() {
    vector<int> nums;
    nums.push_back(3);
    nums.push_back(4);
    nums.push_back(2);
    Solution solution;
    int result = solution.deleteAndEarn(nums);
    cout << result<<endl;
    system("pause");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值