算法面试真题详解:最小调整代价

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

上一篇:算法面试真题详解:嵌套列表的加权和II


下一篇:算法面试真题详解:翻转字符串中的单词