Lintcode 背包专题:最小调整代价,杆子分割,换硬币

一、最小调整代价

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

样例

对于数组[1, 4, 2, 3]和target=1,最小的调整方案是调整为[2, 3, 2, 3],调整代价之和是2。返回2。

思路: 我们规定每个位置出现的数字都在0-100以内,然后先得出第一个数字上出现0-100的调整代价,最后得出第一行的调整代价,然后从第二行开始基于第一行上次调整后的数字进行调整,这时候就要注意target的约束条件了。然后比较调整后是不是变小了,如果变小了,就更新下。 以后的每一行都基于此。

代码:

    public static int MinAdjustmentCost(List<Integer> A, int target) {
        // write your code here
       int len = A.size();

       int[][] f = new int[len][101];

        for (int i = 0; i <= 100; i++) {
            f[0][i] = Math.abs(A.get(0)-i);
        }

        for (int i = 1; i < len; i++) {
            for (int j = 0; j <= 100; j++) {
                f[i][j] = Integer.MAX_VALUE;     // 赋初值
            }
        }

        for (int i = 1; i < len; i++) {
            for (int j = 0; j <= 100; j++) {
                if(f[i-1][j]!=Integer.MAX_VALUE){
                    for (int k = 0; k <= 100; k++) {
                        if(Math.abs(j-k)<=target){
                            f[i][k] = Math.min(f[i][k],f[i-1][j]+Math.abs(k-A.get(i)));
                        }
                    }
                }
            }
        }
        int res = Integer.MAX_VALUE;
        for (int i = 0; i <= 100; i++) {
            res = Math.min(res, f[len-1][i]);
        }
        return res;
    }

二、杆子分割

描述

给一个 n 英寸长的杆子和一个包含所有小于 n 的尺寸的价格. 确定通过切割杆并销售碎片可获得的最大值.例如,如果棒的长度为8,并且不同长度部件的值如下,则最大可获得值为 22(通过切割两段长度 2 和 6 )

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

样例

长度    | 1   2   3   4   5   6   7   8  
--------------------------------------------
价格    | 1   5   8   9  10  17  17  20

给出 price = [1, 5, 8, 9, 10, 17, 17, 20], n = 8 返回 22//切成长度为 2 和 6 的两段

长度    | 1   2   3   4   5   6   7   8  
--------------------------------------------
价格    | 3   5   8   9  10  17  17  20

给出 price = [3, 5, 8, 9, 10, 17, 17, 20], n = 8 返回 24//切成长度为 1 的 8 段

思路:仔细分析下题目,其实就是一个完全背包问题,每个长度的分段都可以重复使用。

完全背包问题的转移方程:


但是可以使用一个一维的数组从左到右遍历,f(i,v) 其实就是f(v),然后f(i-1,v-k*c[i])其实就是f(v-k*c[i]。

完全背包的代码如下:

public class Solution {
    public int backPackIII(int[] A, int[] V, int m) {
        int[] dp = new int[m+1];
        for (int i = 0; i < A.length; i++) {
            for (int j = 1; j <= m; j++) {
                if (j >= A[i]) dp[j] = Math.max(dp[j], dp[j-A[i]]+V[i]);
            }
        }
        return dp[m];
    }
}

本题的代码如下:

    public int cutting(int[] prices, int n) {
        // Write your code here
        int[] f = new int[n+1];
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <=n ; j++) {
                if(j>=i){
                    f[j] = Math.max(f[j],f[j-i]+prices[i-1]);
                }
            }
        }
        return f[n];
    }

三、换硬币

描述

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

样例

给出 coins = [1, 2, 5], amount = 11
返回 3 (11 = 5 + 5 + 1)
给出 coins = [2], amount = 3
返回 -1

代码:
    public int coinChange(int[] coins, int amount) {
        // write your code here
        if(amount<0){
            return -1;
        }
        if(amount==0){
            return 0;
        }
        int sum[] = new int[amount+1];
        for (int i = 0; i < coins.length; i++) {
            if(coins[i]<=amount && coins[i]!=0){
                sum[coins[i]] = 1;
            }
        }

        for (int i = 1; i <= amount; i++) {
            sum[i] = -1;
            for (int j = 0; j < coins.length; j++) {
                if(i>=coins[j] && sum[i-coins[j]]!=-1){
                    if(sum[i-coins[j]]+1<sum[i] || sum[i]==-1){
                        sum[i] = sum[i-coins[j]]+1;
                    }
                }
            }
        }
        return sum[amount];
    }

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值