题目来源:LeetCode_740 删除并获得点数
第一眼看到这个题目的确就会想到打家劫舍问题,隔壁的屋子不能连续偷。
就想着拿二维数组记录数字和他对应出现的次数。然后动态转移方程就是
dp[n] = dp[n-1] + 对应的数字数量 (nums[n] != nums[n-1]+1)
max{dp[n-2]+对应的数字数量, dp[n-1]}.
public int deleteAndEarn(int[] nums) {
Set<Integer> set = new HashSet<>();
for(int i = 0; i<nums.length;i++){
set.add(nums[i]);
}
int n = set.size();
int[][] data = new int[n][2];
Arrays.sort(nums);
data[0][0] = nums[0];
data[0][1] = 1;
int index = 0;
for (int i = 1; i < nums.length;i++){
if (nums[i]!=nums[i-1]){
data[++index][0] = nums[i];
data[index][1] = 1;
}else{
data[index][1] += 1;
}
}
int[] dp = new int[n+1];
dp[1] = data[0][0] * data[0][1];
for(int i = 2; i <= n; i++ ){
if(data[i-1][0]!=data[i-2][0]+1){
dp[i] = dp[i-1] + data[i-1][0] * data[i-1][1];
}else{
dp[i] = Math.max(dp[i-2] + data[i-1][0] * data[i-1][1], dp[i-1]);
}
}
return dp[n];
}
发现时间复杂度太高了直接简化一下,用一个sum数组表示sum[x] = x * x在nums中出现的次数。
再进行动态规划
public int deleteAndEarn(int[] nums) {
int maxValue = 0;
// 得到nums数组中的最大数
for(int i : nums){
maxValue = Math.max(maxValue, i);
}
int[] sum = new int[maxValue + 1]; // sum数组里面存储的数为sum[x] 为 x*nums中x的数量;
for(int i : nums){
sum[i] += i;
}
//然后用动态规划思路(打家劫舍问题)
int[] dp = new int[maxValue + 1];
dp[1] = sum[1];
for(int i = 2; i <= maxValue; i++){
dp[i] = Math.max(dp[i-2] + sum[i], dp[i-1]);
}
return dp[maxValue];
}
此时时间复杂度是降低了,但空间复杂度还有优化的空间。
在动态规划部分,我们发现i状态只和前两个状态有关系
//然后用动态规划思路(打家劫舍问题)将数组简化成两个int
int first = 0 , secend = sum[0];
for(int i = 1; i <= maxValue; i++){
int temp = secend;
secend = Math.max(first + sum[i], secend);
first = temp;
}
return secend;