📜  从1到N合并数字的最低成本(1)

📅  最后修改于: 2023-12-03 14:49:20.163000             🧑  作者: Mango

从1到N合并数字的最低成本

合并数字是指将数列中的数字两两合并,每次合并的代价为这两个数字的和。例如,数列[1, 2, 3, 4, 5]合并为[(1+2), (3+4), 5]的代价为3+7=10。现在给定一个长度为N的数列,如何将它们按照从小到大的顺序合并,使得最终的代价最小。

解法

这是一个经典的动态规划问题,可以用递归和记忆化搜索来解决。首先定义一个函数f(l, r),表示合并数列中下标从l到r的数字的最小代价。递归的边界情况为f(l, l)=0;如果l<r,则将数列分为两个区间[l, mid]和[mid+1, r],对应的代价为f(l, mid)和f(mid+1, r);最后还需要合并这两个区间,对应的代价为sum(l, r),其中sum(l, r)表示数列中下标从l到r的数字和。

具体来说,假设我们已经计算出了所有f(l, mid)和f(mid+1, r),现在需要计算f(l, r)。我们枚举一个分割点k,将数列分成[l, k]和[k+1, r]两个区间,对应的代价是f(l, k)+f(k+1, r)+sum(l, r)。最小的代价就是f(l, r)的取值。

为了避免重复计算,在递归的过程中用一个数组dp来保存计算结果,如果一个状态已经被计算过就直接返回。

具体的代码如下:

public int getMergeCost(int[] nums) {
    int n = nums.length;
    int[][] dp = new int[n][n];

    return f(0, n - 1, nums, dp);
}

private int f(int l, int r, int[] nums, int[][] dp) {
    if (l == r) return 0;
    if (dp[l][r] > 0) return dp[l][r];

    int res = Integer.MAX_VALUE;
    for (int k = l; k < r; k++) {
        int leftCost = f(l, k, nums, dp);
        int rightCost = f(k + 1, r, nums, dp);
        int mergeCost = sum(nums, l, r);
        res = Math.min(res, leftCost + rightCost + mergeCost);
    }

    dp[l][r] = res;
    return res;
}

private int sum(int[] nums, int l, int r) {
    int res = 0;
    for (int i = l; i <= r; i++) {
        res += nums[i];
    }
    return res;
}

时间复杂度为O(n^3),空间复杂度为O(n^2)。

总结

本文介绍了一个经典的动态规划问题,也讲解了如何使用递归和记忆化搜索来解决它。实际上,这里的算法还有一个更高效的实现,叫做矩阵链乘法。这个算法的时间复杂度为O(n^3),但是空间复杂度为O(n^2)。如果感兴趣,可以自行了解。

参考文献:

  • 算法基础课,第11章,动态规划2。

  • 矩阵链乘法的实现(Java):

    public int matrixChainOrder(int[] p) {
        int n = p.length - 1;
        int[][] m = new int[n][n];
    
        for (int len = 2; len <= n; len++) {
            for (int i = 0; i <= n - len; i++) {
                int j = i + len - 1;
                m[i][j] = Integer.MAX_VALUE;
                for (int k = i; k < j; k++) {
                    m[i][j] = Math.min(m[i][j], m[i][k] + m[k + 1][j] + p[i] * p[k + 1] * p[j + 1]);
                }
            }
        }
    
        return m[0][n - 1];
    }