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号
浙公网安备 33010602011771号