算法练习(32):Delete and Earn


题意:给出一个数组,定义一个操作,从中取一个数可以获取数字表示的分数,然后要把与这个数字差的绝对值为1的数都从数组中删掉(意味着你再也得不到他们表示的分数)

分析与思路:这是一道很明显的动态规划题目,当然按照这个题意还不容易想出状态转移方程,先从题意找出规律来简化一下,要取某个数时,其他等于他的数在最后肯定都会取完,因此很容易想到把重复数字归一化,然后得出每个数代表的价值(数字*个数)。然后排序,从小到大,只分析前面跟当前的制约关系。设dp[i]代表在遍历了前i个数并作出选择时对应的当前最大获取分数。对于每个数只有两种选择,选或者不选。

所以状态转移方程:

set[i]==set[i-1]时,dp[i]=(dp[i-2]+value[i])>dp[i-1]?(dp[i-2]+value[i]):dp[i-1]

else dp[i]=dp[i-1]+value[i]

代码:

class Solution {
public:
	int deleteAndEarn(vector<int>& nums) {
		if (nums.size() == 0) return 0;
		vector<int> dataSet;//数组的无重复数字版本
		vector<int> dataValue;//dataSet对应的每个数的总价值
		for (int i = 0; i < nums.size(); i++) {
			int j = 0;
			for (j = 0; j < dataSet.size(); j++) {
				if (dataSet[j] == nums[i]) {
					dataValue[j] += nums[i];
					break;
				}
			}
			if (j == dataSet.size()) {
				dataSet.push_back(nums[i]);
				dataValue.push_back(nums[i]);
			}
		}
		for (int i = 0; i < dataSet.size()-1; i++) {//排序
			for (int j = i + 1; j < dataSet.size(); j++) {
				if (dataSet[j] < dataSet[i]) {
					int temp = dataSet[j];
					dataSet[j] = dataSet[i];
					dataSet[i] = temp;
					temp = dataValue[i];
					dataValue[i] = dataValue[j];
					dataValue[j] = temp;
				}
			}
		}
		int* dp = new int[dataSet.size()];
		dp[0] = dataValue[0];
		if (dataSet.size() == 1) return dp[0];
		if (dataSet[0] == dataSet[1] - 1) dp[1] = dp[0] > dataValue[1] ? dp[0] : dataValue[1]; 
		else dp[1] = dp[0] + dataValue[1];
		if (dataSet.size() == 2) return dp[1];
		for (int i = 2; i < dataSet.size(); i++) {
			if (dataSet[i - 1] == dataSet[i] - 1) {
				int temp = dp[i - 2] + dataValue[i];
				dp[i] = temp > dp[i - 1] ? temp : dp[i - 1];
			}
			else {
				dp[i] = dp[i - 1] + dataValue[i];
			}
		}
		int result = dp[dataSet.size() - 1];
		delete[] dp;
		return result;
	}
};


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值