删除并获得点数
难度:
标签:
题目描述
代码结果
运行时间: 36 ms, 内存: 17.7 MB
/*
思路:
1. 使用Java Stream来统计每个数字出现的次数。
2. 使用IntStream.rangeClosed遍历从1到最大值的所有数字。
3. 使用一个数组存储每个数字的最大点数。
4. 使用mapToObj将每个数字映射成对应的最大点数,并使用reduce找到最大值。
*/
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class SolutionStream {
public int deleteAndEarn(int[] nums) {
if (nums == null || nums.length == 0) return 0;
Map<Integer, Integer> countMap = Arrays.stream(nums)
.boxed()
.collect(Collectors.toMap(x -> x, x -> 1, Integer::sum));
int maxVal = Arrays.stream(nums).max().orElse(0);
int[] dp = new int[maxVal + 1];
dp[0] = 0;
dp[1] = countMap.getOrDefault(1, 0) * 1;
IntStream.rangeClosed(2, maxVal).forEach(i -> {
int earn = i * countMap.getOrDefault(i, 0);
dp[i] = Math.max(dp[i - 1], dp[i - 2] + earn);
});
return dp[maxVal];
}
}
解释
方法:
该题解使用动态规划的思路来解决问题。首先统计每个数字出现的次数,存储在 vec 数组中。然后创建一个 dp 数组,其中 dp[i] 表示考虑前 i 个数字时可以获得的最大点数。对于每个数字 i,可以选择删除它并获得 vec[i]*i 的点数,或者不删除它。如果删除它,那么就不能删除 i-1,此时的最大点数为 dp[i-2]+vec[i]*i;如果不删除它,那么最大点数为 dp[i-1]。最后返回 dp 数组的最后一个元素即为最大获得点数。
时间复杂度:
O(n+m)
空间复杂度:
O(m)
代码细节讲解
🦆
在动态规划解法中,如何确定数组`vec`和`dp`的长度以及它们的初始值是什么意义?
▷🦆
为什么在处理动态规划的状态转移时,选择`dp[i-2] + vec[i] * i`作为一种可能的状态?这种选择背后的逻辑是什么?
▷🦆
在动态规划的实现中,`dp[1] = max(vec[1], vec[0])`这一初始化步骤的具体含义是什么?为什么不是`dp[1] = vec[1] + vec[0]`?
▷🦆
题解中提到如果`max_num < 2`,则返回`nums.count(1)`,这里的逻辑是否适用于所有小于2的`max_num`情况?
▷相关问题
打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例 1:
输入:[1,2,3,1] 输出:4 解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。 偷窃到的最高金额 = 1 + 3 = 4 。
示例 2:
输入:[2,7,9,3,1] 输出:12 解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。 偷窃到的最高金额 = 2 + 9 + 1 = 12 。
提示:
1 <= nums.length <= 100
0 <= nums[i] <= 400