給一個整數數組,調整每個數的大小,使得相鄰的兩個數的差不大于一個給定的整數target,調整每個數的代價為調整前後的差的絕對值,求調整代價之和最小是多少。
你可以假設數組中每個整數都是正整數,且小于等于100。
線上評測位址:
領扣題庫官網樣例1:
輸入: [1,4,2,3], target=1
輸出: 2
樣例2:
輸入: [3,5,4,7], target=2
輸出: 1
算法:dp
思路
已知每個整數範圍[1,100],那麼對于每個元素,為了調整到該元素和與之相鄰的元素的差不大于target,該元素調整的範圍就在[1,100]。是以對于數組A[]的每一位元素,我們都需要進行[1,100]範圍内的可能狀态的轉移。
令dpi表示元素A[i]=j時,A[i]與A[i-1]內插補點不大于target所需要付出的最小代價。
當A[i]=j時,可行的A[i-1]的範圍為[max(1, j - target),min(100, j + target)]。而dpi為所有可行的A[i-1]中,花費代價最小的一種可能,再加上A[i]調整到 j 所需花費abs(j - A[i])。
當A[i]=j時,k在[max(1, j - target),min(100, j + target)]範圍内時,我們可以寫出以下式子:
1.臨界值:
dp0 = abs(j - A[0])
2.狀态轉移方程:
dpi = min(dpi, dpi - 1 + abs(j - A[i]))
最後在所有最後一位的可能解dpn-1中的最小值,就是我們所求的最小代價。
複雜度
假設數組長度為n
空間複雜度O(10000*n)
時間複雜度O(n^2)
題解:
public class Solution {
/*
* @param A: An integer array
* @param target: An integer
* @return: An integer
*/
public int MinAdjustmentCost(List<Integer> A, int target) {
int n = A.size();
// dp[i][j]表示元素A[i]=j時,A[i]與A[i-1]內插補點不大于target所需要付出的最小代價
int[][] dp = new int[n][101];
for (int i = 0; i < n; i++) {
for (int j = 1; j <= 100; j++) {
// 初始化為極大值
dp[i][j] = Integer.MAX_VALUE;
}
}
for (int i = 0; i < n; i++) {
for (int j = 1; j <= 100; j++) {
if (i == 0) {
// 臨界值:第一個元素A[0]調整為j的代價
dp[0][j] = Math.abs(j - A.get(0));
}
else {
// left為A[i]=j時,A[i-1]與A[i]內插補點不大于target的A[i-1]最小值
// right為A[i]=j時,A[i-1]與A[i]內插補點不大于target的A[i-1]最大值
int left = Math.max(1, j - target);
int right = Math.min(100, j + target);
for (int k = left; k <= right; k++) {
// 當A[i-1]=k時,答案為A[i-1]=k的代價dp[i-1][k],加上A[i]=j的調整代價abs(j-A[i])
dp[i][j] = Math.min(dp[i][j], dp[i - 1][k] + Math.abs(j - A.get(i)));
}
}
}
}
int mincost = Integer.MAX_VALUE;
for (int i = 1; i <= 100; i++) {
mincost = Math.min(mincost, dp[n - 1][i]);
}
return mincost;
}
}
更多題解參考:
九章官網solution