牛客NC59 矩阵的最小路径和 (动态规划,压缩空间的动态规划)

这篇博客探讨了如何使用动态规划解决找到二维矩阵中从左上角到右下角的最小路径和问题。首先介绍了暴力递归解法,虽然能求解但时间复杂度过高。接着详细阐述了动态规划的优化方案,包括标准动态规划和压缩空间的动态规划,两者都能将时间复杂度降低到O(n*m),其中压缩空间的动态规划进一步降低了空间复杂度到O(n)。通过这些方法,可以更高效地解决此类问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题链接

暴力递归(时间复杂度过高)

每个位置都尝试向右走和向左走,时间复杂度较高,为 O(2 ^ (n * m))

public class Solution{
    private int minPathSum;

    /**
     * @param matrix int整型二维数组 the matrix
     * @return int整型
     */
    public int minPathSum (int[][] matrix) {
        // write code here
        int n = matrix.length;
        if (n == 0) return 0;
        int m = matrix[0].length;

        minPathSum = Integer.MAX_VALUE;
        findMinPathSum(0, 0, n - 1, m - 1, matrix, 0);

        return minPathSum;
    }
    /**
     * 暴力递归,每个位置都尝试向右和向下两种走法,
     *      时间复杂度较高,为 O(2 ^ (n * m))
     * @param matrix int整型二维数组 the matrix
     * @return int整型
     */
    private void findMinPathSum(int i, int j, int maxI, int maxJ, int[][] matrix, int pathSum) {
        if (i > maxI || j > maxJ)
            return;

        pathSum += matrix[i][j];
        if (i == maxI && j == maxJ) {
            minPathSum = Math.min(pathSum, minPathSum);
            return;
        }

        findMinPathSum(i + 1, j, maxI, maxJ, matrix, pathSum);
        findMinPathSum(i, j + 1, maxI, maxJ, matrix, pathSum);
    }
}

动态规划

时间复杂度 O(n * m),空间复杂度O(n * m)

    /**
     * 动态规划,时间复杂度 O(n * m),空间复杂度O(n * m)
     *      状态dp[i][j],从起点到达matrix[i][j]的最小路径
     *
     *       状态初始化:
     *           dp[0][0] = matrix[0][0];
     *           for (int i = 0; i < n - 1; i++){
     *             dp[i + 1][0] = matrix[i + 1][0] + dp[i][0];
     *           }
     *            for (int j = 0; j < m - 1; j++){
     *             dp[0][j + 1] = matrix[0][j + 1] + dp[0][j];
     *           }
     *
     *      状态转移方程:
     *          dp[i][j] = matrix[i][j] + Math.min(dp[i][j - 1], dp[i - 1][j]) (前提是数组不越界)
     *
     * @param matrix int整型二维数组 the matrix
     * @return int整型
     */
    public int minPathSum (int[][] matrix) {
        // write code here
        int n = matrix.length;
        if (n == 0) return 0;
        int m = matrix[0].length;

        int[][] dp = new int[n][m];

        dp[0][0] = matrix[0][0];
        for (int i = 0; i < n - 1; i++){
            dp[i + 1][0] = matrix[i + 1][0] + dp[i][0];
        }
        for (int j = 0; j < m - 1; j++){
            dp[0][j + 1] = matrix[0][j + 1] + dp[0][j];
        }

        for (int i = 1; i < n; i++) {
            for (int j = 1; j < m; j++)
                dp[i][j] = matrix[i][j] + Math.min(dp[i - 1][j], dp[i][j - 1]);
        }

        return dp[n - 1][m - 1];
    }

压缩空间的动态规划(可以降低空间复杂度)

该压缩空间的方法几乎可以用到所有二维动态规划表。

    /**
     * 压缩空间的动态规划,时间复杂度 O(n * m),空间复杂度O(n)
     *      由于我们的动态规划,从起点开始,按从左到右,从上到下的顺序遍历,所以
     *      可以将二维的状态变量压缩成一维的状态变量 (既不需要考虑行号)
     *
     *      状态dp[i]:
     *                 更新之前,
     *                      dp[i - 1]表示到当前位置matrix[][i + 1]的左一位置的最小路径
     *                      dp[i]表示到当前位置matrix[][i + 1]的上一位置的最小路径
     *                 更新之后,
     *                      dp[i]表示到当前位置matrix[][i + 1]的最小路径
     *
     *      状态初始化:
     *         int[] dp = new int[m + 1];
     *         for (int i = 0; i < m + 1; i++)
     *             dp[i] = Integer.MAX_VALUE;
     *         dp[1] = 0;
     *
     *      状态转移方程:
     *          dp[i] = Math.min(dp[i - 1], dp[i]) + matrix[i - 1][j - 1]; (前提是数组不越界)
     *
     * @param matrix int整型二维数组 the matrix
     * @return int整型
     */
    public int minPathSum3 (int[][] matrix) {
        // write code here
        int n = matrix.length;
        if (n == 0) return 0;
        int m = matrix[0].length;

        int[] dp = new int[m + 1];
        // 状态初始化
        for (int i = 0; i < m + 1; i++)
            dp[i] = Integer.MAX_VALUE;
        dp[1] = 0;

        // 动态规划
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++)
                dp[j] = Math.min(dp[j - 1], dp[j]) + matrix[i - 1][j - 1];
        }

        return dp[m];
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值