91. Minimum Adjustment Cost
【题目】
Given an integer array, adjust each integers so that the difference of every adjacent integers are not greater than a given number target.
If the array before adjustment is A, the array after adjustment is B, you should minimize the sum of |A[i]-B[i]|
给一个整数数组,调整每个数的大小,使得相邻的两个数的差小于一个给定的整数target,调整每个数的代价为调整前后的差的绝对值,求调整代价之和最小是多少。
你可以假设数组中每个整数都是正整数,且小于等于100。你可以假设数组中每个整数都是正整数,且小于等于100。
【例子】
对于数组
[1, 4, 2, 3]
和target=
1
,最小的调整方案之一是调整为[2, 3, 2, 3],调整代价之和是2。返回2。
【思路】
因为数的范围是1~100,每个数有100中调整的可能性,采用动态规划的思路。
建立大小为(n+1)*101的二维数组rec记录所有可能调整的代价,第一行初始化为全0,其他行为最大值。
rec中第i行对应A[i-1]。对于每个数A[i],调整后的结果有100种,用rec[i][j]表示数字A[i]调整为j的最小代价。对于每个rec[i][j],A[i-1]调整到k的代价加上A[i]调整到j的最小代价即为rec[i][j]的代价。而k又有100种选择,对于j,当|j-k|的绝对值不大于target时,代价最小,当前rec[i][j]为rec[i-1][k] +( j – A[i-1]),rec[i][j]保留所有可能代价中的最小代价。
最后,rec[n][0~100]中的最小代价即为对整个数组调整后的最下代价。
class Solution {
public:
/**
* @param A: An integer array.
* @param target: An integer.
*/
int MinAdjustmentCost(vector<int> A, int target) {
// write your code here
int n = A.size();
vector<vector<int> > rec(n+1, vector<int> (101, numeric_limits<int>::max()));
//初始化第一行为0
//rec[i][j]表示第i个数调整到j的最小代价,k表示相邻两个数调整到某个值的所有可能
rec[0] = vector<int>(101, 0);
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= 100; ++j) {
for (int k = 0; k <= 100; k++) {
//如果k在target范围内,更新rec[i][j]的值为上一个数到k的代价,加上当前数到j的代价
if (abs(j-k) <= target)
rec[i][j] = min(rec[i-1][k] + abs(A[i-1]-j), rec[i][j]);
}
}
}
int cost = numeric_limits<int>::max();
for (int i = 0; i <= 100; ++i) {
cost = min(cost, rec[n][i]);
}
return cost;
}
};
为什么不能使用一维数组记录最小代价并更新?
因为与背包问题不同,背包问题中的每个物品可以只根据前面的物品放置状况调整,可以用一维数组记录上一个物品调整后的状态,对于当前物品从后往前进行操作,保证使用的都是上一个物品调整后的状态。但本题中,每个位置的数与它前后相邻的数都有关,使用一维数组只能保证左边为之前的状态,右边为当前物品的状态,无法用右边的数进行更新。