LeetCode-62. 不同路径-Java-medium

题目链接

法一(动态规划)
    /**
     * 法一(动态规划)
     * 时间复杂度:O(m * n)
     * 空间复杂度:O(m * n)
     * (1)确定dp数组以及下标的含义
     *     dp[i][j]表示从(0,0)出发,到(i,j)有dp[i][j]条不同的路径
     * (2)确定递推公式
     *     dp[i][j] = dp[i - 1][j] + dp[i][j - 1] // dp[i][j]只有从上方和左方这两个方向过来
     * (3)确定dp数组如何初始化
     *     dp[i][0]和dp[0][j]一定都是1
     * (4)确定遍历顺序
     *     dp[i][j]都是从其上方和左方推导而来,那么从左到右一层一层遍历就可以了
     *
     * @param m
     * @param n
     * @return
     */
    public int uniquePaths(int m, int n) {
        int[][] dp = new int[m][n];
        for (int i = 0; i < m; i++) {
            dp[i][0] = 1;
        }
        for (int j = 0; j < n; j++) {
            dp[0][j] = 1;
        }
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
            }
        }
        return dp[m - 1][n - 1];
    }
法二(动态规划 + 滚动数组)
    /**
     * 法二(动态规划 + 滚动数组)
     * 时间复杂度:O(m * n)
     * 空间复杂度:O(n)
     * 滚动数组
     * (1)滚动数组是一种能够在动态规划中降低空间复杂度的方法
     * (2)有时某些二维dp方程可以直接降阶到一维,在某些题目中甚至可以降低时间复杂度
     * (3)通过观察dp方程来判断需要使用哪些数据,可以抛弃哪些数据,一旦找到关系,就可以用新的数据不断覆盖旧的数据来减少空间的使用
     *
     * @param m
     * @param n
     * @return
     */
    public int uniquePaths_2(int m, int n) {
        int[] dp = new int[n];
        for (int i = 0; i < n; i++) {
            dp[i] = 1;
        }
        for (int i = 1; i < m; i++) { // 从上到下
            for (int j = 1; j < n; j++) { // 从左到右
                dp[j] += dp[j - 1];
            }
        }
        return dp[n - 1];
    }
法三(组合)
    /**
     * 法三(组合)
     * 时间复杂度:O(min(m,n))
     * 空间复杂度:O(1)
     * 排列组合概念
     * (1)排列
     *     从n个不同元素中取出m(m<=n)个元素的排列数,用符号A(n,m)表示,规定0! = 1
     *     A(n,m) = n*(n-1)*...*(n-m+1) = n!/(n-m)!
     * (2)组合
     *     从n个不同元素中取出m(m<=n)个元素的组合数,用符号C(n,m)表示,规定0! = 1
     *     C(n,m) = A(n,m)/m! = C(n,n-m)
     * 思路:
     * (1)一共m,n的话,无论怎么走,走到终点都需要m+n-2步
     * (2)在这m+n-2步中,一定有m-1步是要向下走的,不用管什么时候向下走
     * (3)可以转化为,给你m+n-2个不同的数,随便取m-1个数,有几种取法,直接计算C(m+n-2,m-1)即可
     * (4)C(m+n-2,m-1) = C(m+n-2,n-1) = C(m+n-2,min(m-1,n-1)) = (m+n-2)! / ((n-1)!(m-1)!)
     *
     * @param m
     * @param n
     * @return
     */
    public int uniquePaths_3(int m, int n) {
        int up = m + n - 2; // 分子
        int down = Math.min(m - 1, n - 1); // 分母min(m - 1, n - 1)!是保留下来的,其余的跟分子抵消了
        double ans = 1.0; // 防止溢出
        while (down > 0) { // 保留下来的分子和分母阶乘的次数相等
            ans *= up * 1.0 / down;
            up--;
            down--;
        }
        return (int) (ans + 0.5); // 四舍五入
    }
本地测试
        /**
         * 62. 不同路径
         */
        lay.showTitle(62);
        Solution62 sol62 = new Solution62();
        System.out.println(sol62.uniquePaths(3, 7));
        System.out.println(sol62.uniquePaths_2(3, 7));
        System.out.println(sol62.uniquePaths_3(3, 7));
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值