动态规划模块

最小调整代价

描述

给一个整数数组,调整每个数的大小,使得相邻的两个数的差不大于一个给定的整数target,调整每个数的代价为调整前后的差的绝对值,求调整代价之和最小是多少。

样例

样例 1:
	输入:  [1,4,2,3], target=1
  输出:  2

样例 2:
	输入:  [3,5,4,7], target=2
	输出:  1

代码

public class Solution {
    /*
     * @param A: An integer array
     * @param target: An integer
     * @return: An integer
     */
    public int MinAdjustmentCost(List<Integer> A, int target) {
        if(A == null || A.size() == 0) return 0;
        int n = A.size();
        int[][] dp = new int[n + 1][101];
        for(int i = 0; i <= n; i++){
            for(int j = 0; j <= 100; j++){
                dp[i][j] = Integer.MAX_VALUE;
            }
        }
        for(int i = 0; i <= 100; i++){
            dp[0][i] = 0;
        }
        for(int i = 1; i <= n; i++){
            for(int j = 0; j <= 100; j++){
                if(dp[i - 1][j] != Integer.MAX_VALUE){
                    for(int k = 0; k <= 100; k++){
                        if(Math.abs(j - k) <= target){
                            if(dp[i][k] > dp[i - 1][j] + Math.abs(A.get(i - 1) - k)){
                                dp[i][k] = dp[i - 1][j] + Math.abs(A.get(i - 1) - k);
                            }
                        }
                    }
                }
            }
        }
        int ans = Integer.MAX_VALUE;
        for(int i = 0; i <= 100; i++){
            if(ans > dp[n][i]){
                ans = dp[n][i];
            }
        }
        return ans;
    }
}

背包问题

描述

在n个物品中挑选若干物品装入背包,最多能装多满?假设背包的大小为m,每个物品的大小为A[i]

样例

Example 1:
	Input:  [3,4,8,5], backpack size=10
	Output:  9

Example 2:
	Input:  [2,3,5,7], backpack size=12
	Output:  12

代码

public class Solution {
    /**
     * @param m: An integer m denotes the size of a backpack
     * @param A: Given n items with size A[i]
     * @return: The maximum size
     */
    public int backPack(int m, int[] A) {
        int n = A.length;
        boolean[][] dp = new boolean[n + 1][m + 1];
        for(int i = 0; i <= n; i++){
            for(int j = 0; j <= m; j++){
                dp[i][j] = false;
            }
        }
        dp[0][0] = true;
        for(int i = 1; i <= n; i++){
            for(int j = 0; j <= m; j++){
                dp[i][j] = dp[i - 1][j];
                if(j >= A[i - 1] && dp[i - 1][j - A[i - 1]]){
                    dp[i][j] = true;
                }
            }
        }
        for(int i = m; i >= 0; i--){
            if(dp[n][i]){
                return i;
            }
        }
        return 0;
    }
}

约翰的后花园

描述

约翰想在他家后面的空地上建一个后花园,现在有两种砖,一种3 dm的高度,7 dm的高度。约翰想围成xdm的墙。如果约翰能做到,输出YES,否则输出NO。

样例

Example 1:

Input : x = 10
Output : "YES"
Explanation :
x = 3 + 7:That is, you need one batch of 3 dm height bricks and one batch of 7 dm height bricks.
Example 2:

Input : x = 5
Output : "NO"
Explanation:
John can not enclose a high 5 dm wall with 3 dm height bricks and 7 dm height bricks.
Example 3:

Input : x = 13
Output : "YES"
Explanation :
x = 2 * 3 + 7:That is, you need two batch of 3 dm height bricks and one batch of 7 dm height bricks.

代码

public class Solution {
    /**
     * @param x: the wall's height
     * @return: YES or NO
     */
    public String isBuild(int x) {
        boolean[] dp = new boolean[x + 1];
        for(int i = 3; i <= x; i++){
            if(i == 3 || i == 7){
                dp[i] = true;
                continue;
            }
            if(i < 7){
                dp[i] = dp[i - 3];
            }
            else{
                dp[i] = dp[i - 3] || dp[i - 7];
            }
        }
        if(dp[x]) return "YES";
        else return "NO";
    }
}

背包问题II

描述

有 n 个物品和一个大小为 m 的背包. 给定数组 A 表示每个物品的大小和数组 V表示每个物品的价值.

问最多能装入背包的总价值是多大?

  1. A[i], V[i], n, m 均为整数
  2. 你不能将物品进行切分
  3. 你所挑选的要装入背包的物品的总大小不能超过 m

样例 1:

输入: m = 10, A = [2, 3, 5, 7], V = [1, 5, 2, 4]
输出: 9
解释: 装入 A[1] 和 A[3] 可以得到最大价值, V[1] + V[3] = 9 

样例 2:

输入: m = 10, A = [2, 3, 8], V = [2, 5, 8]
输出: 10
解释: 装入 A[0] 和 A[2] 可以得到最大价值, V[0] + V[2] = 10

代码

public class Solution {
    /**
     * @param m: An integer m denotes the size of a backpack
     * @param A: Given n items with size A[i]
     * @param V: Given n items with value V[i]
     * @return: The maximum value
     */
    public int backPackII(int m, int[] A, int[] V) {
        int n = A.length;
        int[][] dp = new int[n + 1][m + 1];
        for(int i = 0; i <= n; i++){
            for(int j = 0; j <= m; j++){
                if(i == 0 || j == 0){
                    dp[i][j] = 0;
                }
                else if(A[i - 1] > j){
                    dp[i][j] = dp[i - 1][j];
                }
                else if(j >= A[i - 1]){
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - A[i - 1]] + V[i - 1]);
                }
            }
        }
        return dp[n][m];
    }
}

换硬币

描述

给出不同面额的硬币以及一个总金额. 写一个方法来计算给出的总金额可以换取的最少的硬币数量. 如果已有硬币的任意组合均无法与总金额面额相等, 那么返回 -1.

你可以假设每种硬币均有无数个

样例1

输入:
[1, 2, 5]
11
输出: 3
解释: 11 = 5 + 5 + 1

样例2

输入: 
[2]
3
输出: -1

代码

这是一个典型的完全背包问题。
设dp[i][j]表示使用前i个硬币,总金额为j时需要的最少硬币数量。

dp[i][j]=max(dp[i-1][j],dp[i-1][j-k*coin[i]]+k) \quad (0\leq k*coin[i] \leq j)dp[i][j]=max(dp[i−1][j],dp[i−1][j−k∗coin[i]]+k)(0≤k∗coin[i]≤j)

public class Solution {
    /**
     * @param coins: a list of integer
     * @param amount: a total amount of money amount
     * @return: the fewest number of coins that you need to make up
     */
    public int coinChange(int[] coins, int amount) {
        int[] dp = new int[amount + 1];
        dp[0] = 0;
        for(int i = 1; i <= amount; i++){
            dp[i] = -1;
            for(int j = 0; j < coins.length; j++){
                if(i >= coins[j] && dp[i - coins[j]] != -1){
                    if(dp[i] == -1 || dp[i] > dp[i - coins[j]] + 1){
                        dp[i] = dp[i - coins[j]] + 1;
                    }
                }
            }
        }
        return dp[amount];
    }
}

背包问题III

描述

给定 n 种物品, 每种物品都有无限个. 第 i 个物品的体积为 A[i], 价值为 V[i].

再给定一个容量为 m 的背包. 问可以装入背包的最大价值是多少?

  1. 不能将一个物品分成小块.
  2. 放入背包的物品的总大小不能超过 m.

样例

样例 1:

输入: A = [2, 3, 5, 7], V = [1, 5, 2, 4], m = 10
输出: 15
解释: 装入三个物品 1 (A[1] = 3, V[1] = 5), 总价值 15.

样例 2:

输入: A = [1, 2, 3], V = [1, 2, 3], m = 5
输出: 5
解释: 策略不唯一. 比如, 装入五个物品 0 (A[0] = 1, V[0] = 1).

代码

public class Solution {
    /**
     * @param A: an integer array
     * @param V: an integer array
     * @param m: An integer
     * @return: an array
     */
    public int backPackIII(int[] A, int[] V, int m) {
        int n = A.length;
        int[][] dp = new int[n + 1][m + 1];
        for(int i = 1; i <= n; i++){
            for(int j = 0; j <= m; j++){
                dp[i][j] = dp[i - 1][j];
                if(j >= A[i - 1]){
                    dp[i][j] = Math.max(dp[i][j - A[i - 1]] + V[i - 1], dp[i][j]);
                }
            }
        }
        return dp[n][m];
    }
}

背包问题IV

描述

给出 n 个物品, 以及一个数组, nums[i]代表第i个物品的大小, 保证大小均为正数并且没有重复, 正整数 target 表示背包的大小, 找到能填满背包的方案数。
每一个物品可以使用无数次

您在真实的面试中是否遇到过这个题?  是

题目纠错

样例

样例1

输入: nums = [2,3,6,7] 和 target = 7
输出: 2
解释:
方案有: 
[7]
[2, 2, 3]

样例2

输入: nums = [2,3,4,5] 和 target = 7
输出: 3
解释:
方案有: 
[2, 5]
[3, 4]
[2, 2, 3]

代码

public class Solution {
    /**
     * @param nums: an integer array and all positive numbers, no duplicates
     * @param target: An integer
     * @return: An integer
     */
    public int backPackIV(int[] nums, int target) {
        int n = nums.length;
        int[][] dp = new int[n + 1][target + 1];
        dp[0][0] = 1;
        for(int i = 1; i <= n; i++){
            for(int j = 0; j <= target; j++){
                int k = 0;
                while(j >= k * nums[i - 1]){
                    dp[i][j] += dp[i - 1][j - k * nums[i - 1]];
                    k++;
                }
            }
        }
        return dp[n][target];
    }
}

背包问题V

描述

给出 n 个物品, 以及一个数组, nums[i] 代表第i个物品的大小, 保证大小均为正数, 正整数 target表示背包的大小, 找到能填满背包的方案数。
每一个物品只能使用一次

样例

给出候选物品集合 [1,2,3,3,7] 以及 target 7

结果的集合为:
[7]
[1,3,3]
public class Solution {
    /**
     * @param nums: an integer array and all positive numbers
     * @param target: An integer
     * @return: An integer
     */
    // dp[n][w] = dp[i - 1][w] + dp[i - 1][w - nums[i - 1]];
    public int backPackV(int[] nums, int target) {
        int n = nums.length;
        int[][] dp = new int[n + 1][target + 1];
        dp[0][0] = 1;
        for(int i = 1; i <= target; i++){
            dp[0][i] = 0;
        }
        for(int i = 1; i <= n; i++){
            for(int j = 0; j <= target; j++){
                dp[i][j] = dp[i - 1][j];
                if(j >= nums[i - 1]){
                    dp[i][j] += dp[i - 1][j - nums[i - 1]];
                }
            }
        }
        return dp[n][target];
    }
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值