动态规划学习(二)
- 删除并获得点数–打家劫舍的进阶版
https://leetcode-cn.com/problems/delete-and-earn/
class Solution {
public int deleteAndEarn(int[] nums) {
//设置一个数量数组sum[],再设置一个价值数组var[]
//(数量数组为了统计数组中个元素的个数,而价值数组则是 各元素的总价值)
int[] sum=new int[10001]; int[] var=new int[10001];
//将nums里的各个数进行统计,放进sum数组里
for(int i=0;i<nums.length;i++){
sum[nums[i]]++;
}
//求出各个元素的总价值
for(int i=0;i<10001;i++){
var[i]=i*sum[i];
}
//之后,题目就变成了打家劫舍(取每个值都有了对应的价值,且不能取相邻的)
//初始化变量
int[] dp=new int[10001];
dp[0]=var[0];
//根据状态方程来赋值
for(int i=1;i<10001;i++){
if(i==1) dp[i]=Math.max(dp[0],var[i]);
//要么不取(dp[i-1]),要么取 dp[i-2]+var[i](var[i]为当前数的价值)
else dp[i]=Math.max(dp[i-1],dp[i-2]+var[i]);
}
//返回结果
return dp[10000];
}
}
动态规划解决缀值问题
关于这部分,他能更加深入的让我们理解动态规划的使用场景。
什么题能用到动态规划?他的标志是什么?
总结下来:应该是:初始值+这个数的值和数组中的值有联系(可以建立状态转移方程)+求最值
这部分一般都会有一个 左面或者右面的初始值如:[0,1) 或者是
(0,1]。
要时刻记住,动态规划求的一般都是左面或者右面一定范围里的最值。
class Solution {
//利用动态规划求出某天之内的最小买入话费,再用这些天的每一天来减去对应的话费即使最小值
public int maxProfit(int[] prices) {
//初始化
int res=0;
int[] dp=new int[prices.length];
dp[0]=prices[0];
//利用状态方程求dp数组的值
for(int i=1;i<prices.length;i++){
dp[i]=Math.min(dp[i-1],prices[i]);
}
//遍历prices数组,求出最大利润
for(int i=0;i<prices.length;i++){
int temp=prices[i]-dp[i];
if(temp>res)res=temp;
}
//返回对应的解
return res;
}
}
- 将每个元素替换为右侧的最大元素–后缀
https://leetcode-cn.com/problems/replace-elements-with-greatest-element-on-right-side/
自己创建 dp 数组做的
class Solution {
public int[] replaceElements(int[] arr) {
//初始化
int[] dp=new int[arr.length];
dp[arr.length-1]=-1;
//利用状态方程求出dp各个元素的值
for(int i=arr.length-2;i>=0;i--){
dp[i]=Math.max(dp[i+1],arr[i+1]);
}
//返回
return dp;
}
}
在原来的数组上直接操作
class Solution {
//在原数组上动态规划
public int[] replaceElements(int[] arr) {
//利用状态方程求出dp各个元素的值
int arrTemp=arr[arr.length-1];
for(int i=arr.length-1;i>=0;i--){
if(i==arr.length-1) arr[arr.length-1]=-1;
else {
int temp=arr[i];
arr[i]=Math.max(arr[i+1],arrTemp);
arrTemp=temp;
}
}
//返回
return arr;
}
}