LeetCode369
3.使数组变美的最小增量运算数
题目概述:给定一数组nums和整数k。可以对数组中任意一个数执行任意次以下操作:使该数加1.现要求使该数组长度大于等于3的子数组中至少含有一个大于等于k的数。问最少需要执行多少次操作,才能达成该目标。
解题思路:首先,要使长度大于等于3的子数组中至少含有一个大于等于k的数,可以转化为:使所有长度等于3的子数组至少含有一个大于等于k的数。进一步思考,将题目转化为:从该数组中选择一些数使其大于等于k,使得所有长度等于3的子数组至少含有一个大于等于k的数。于是,定义数组dp[i][j],i表示当前枚举的数的下标,j表示当前枚举的数右边没有大于等于k的数的数量。倒着枚举,如果当前枚举的数选择变为k,则转移方程为:
dp[i][j] = dfs(i - 1,j) + max(0,k - nums[i]);如果不变为k,则转移方程为:
dp[i][j] = dfs(i - 1,j + 1).但是这种情况有一个条件,j<2.因为如果当前枚举的数右边已经有2个数小于k,那么当前枚举的数就必须要选择变为k。
记忆化搜索
class Solution {
private final int N = 100010;
public long minIncrementOperations(int[] nums, int k) {
long dp[][] = new long[N][3];
//将数组初始化为-1,表示未被计算过
for(long t[] : dp){
Arrays.fill(t,-1);
}
//开始记忆化搜索
return dfs(nums.length - 1,0,dp,nums,k);
}
public long dfs(int i,int j,long dp[][],int nums[],int k){
//已经没有数了,递归结束
if(i < 0){
return 0;
}
//计算过
if(dp[i][j] != -1)return dp[i][j];
//选
long res = dfs(i - 1,0,dp,nums,k) + Math.max(0,k - nums[i]);
//不选
if(j < 2){
res = Math.min(res,dfs(i - 1,j + 1,dp,nums,k));
}
dp[i][j] = res;
return dp[i][j];
}
}
4.收集所有金币可获得的最大积分
题目概述:给定边数组、每个节点上的金币数以及整数k。根节点为0号节点。有两种获得积分的方法:1.获得该节点的金币数-k的积分;2.获得该节点的金币数一半的积分,并且该节点的所有后代节点的金币数都减少一半。问最多可以获得多少积分
解题思路:首先,两种选择就是两个转移方程。memo[i][j]:i表示当前枚举的节点,j表示i之前进行第二种选择的次数。
第一种选择的转移方程:memo[i][j] = dfs(ch,j) + (coins[i] >> j) - k;
第二种选择的转移方程:memo[i][j] = dfs(ch,j + 1) + coins[i] >> (j + 1);
代码:
class Solution {
public int maximumPoints(int[][] edges, int[] coins, int k) {
int N = coins.length;
//创建一个数组,每个数组元素是一个list
List<Integer>g[] = new ArrayList[N];
//让数组中的每个元素都执行new ArrayList<>()操作
Arrays.setAll(g,e -> new ArrayList<>());
//建图
for(int [] edge : edges){
g[edge[0]].add(edge[1]);
g[edge[1]].add(edge[0]);
}
int memo[][] = new int[N][15];
for(int []m:memo){
Arrays.fill(m,-1);
}
return dfs(0,0,-1,g,coins,k,memo);
}
//记忆化搜索
public int dfs(int i,int j,int fa,List<Integer>g[],int[] coins,int k,int memo[][]){
//已搜过,不再搜
if(memo[i][j] != -1)return memo[i][j];
//第一种选择
int res1 = (coins[i] >> j) - k;
//第二种选择
int res2 = coins[i] >> (j + 1);
for(int ch : g[i]){
//由于是无向图,只有是儿子节点才进行操作
if(ch == fa)continue;
res1 += dfs(ch,j,i,g,coins,k,memo);
//j大于等于14时,最大的coins也会变为0
if(j + 1 < 14){
res2 += dfs(ch,j + 1,i,g,coins,k,memo);
}
}
memo[i][j] = Math.max(res1,res2);
return Math.max(res1,res2);
}
}
浙公网安备 33010602011771号