一、最小调整代价
给一个整数数组,调整每个数的大小,使得相邻的两个数的差不大于一个给定的整数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];
}