题意:给出一个数组,定义一个操作,从中取一个数可以获取数字表示的分数,然后要把与这个数字差的绝对值为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;
}
};