不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
(题目来源:力扣(LeetCode))
示例 1:
输入:m = 3, n = 7
输出:28
示例 2:
输入:m = 3, n = 2
输出:3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
1. 向右 -> 向右 -> 向下
2. 向右 -> 向下 -> 向右
3. 向下 -> 向右 -> 向右
示例 3:
输入:m = 7, n = 3
输出:28
示例 4:
输入:m = 3, n = 3
输出:6
提示:
1 <= m, n <= 100
题目数据保证答案小于等于 2 * 109
解决方法一(递归法,自己测试加leecode测试能通过,但是提交就报错):
package com.lxf;
public class UniquePaths {
public static void main(String[] args) {
UniquePaths u=new UniquePaths();
System.out.println("总数="+u.uniquePaths(3, 2));
}
public static int endX;
public static int endY;
public static int[][] next=new int[][]{
{0,1},
{1,0}
};
static int count=0;
public int uniquePaths(int m, int n) {
if(m<1||n<1) {
return 0;
}
if(m==1&&n==1) {
return 1;
}
//赋值目的地坐标
endX=m;
endY=n;
searchPath(0,0);
return count;
}
private void searchPath(int x, int y) {
//如果到了最后一个位置就停,并且步数+1
if(x==(endX-1)&&y==(endY-1)) {
count++;
return;
}
//当前位置向下、向右走
for (int i = 0; i < next.length; i++) {
x+=next[i][0];
y+=next[i][1];
if(x<endX&&y<endY) {
searchPath(x,y);
}
x-=next[i][0];
y-=next[i][1];
}
}
}
解决方法二(dp反推):
package com.lxf;
public class UniquePaths {
public static void main(String[] args) {
System.out.println(uniquePaths(3,2));
}
public static int uniquePaths(int m, int n) {
if(m<1||n<1) {
return 0;
}
//只有一行一列的时候直接返回1
if(m==1&&n==1) {
return 1;
}
//存储结果的数组
int[][] map=new int[m][n];
//赋初始值
//因为只能下右走,所以最后一行和最后一列的步数全都为1(除了它们的交点)
for (int i = 0; i < m; ++i) {
map[i][n-1] = 1;
}
for (int j = 0; j < n; ++j) {
map[m-1][j] = 1;
}
map[m-1][n-1]=0;
//根据规律:本位置的步数=下一步向左+下一步向右(注意考虑边界位置)
//从最后一个位置开始推算前面的步数
for (int i = m-2; i >=0; i--) {
for (int j = n-2; j >=0; j--) {
map[i][j]=map[i+1][j]+map[i][j+1];
}
}
//返回第一个值
return map[0][0];
}
}
dp正推(官方题解,我反正不知道它怎么扯出来的方程):
public int uniquePaths(int m, int n) {
//新建一个存储结果的数组
int[][] f = new int[m][n];
for (int i = 0; i < m; ++i) {
f[i][0] = 1;
}
for (int j = 0; j < n; ++j) {
f[0][j] = 1;
}
for (int i = 1; i < m; ++i) {
for (int j = 1; j < n; ++j) {
f[i][j] = f[i - 1][j] + f[i][j - 1];
}
}
return f[m - 1][n - 1];
}
解决方法三(数学公式,官方题解):
从左上角到右下角的过程中,我们需要移动 m+n-2次,其中有 m-1 次向下移动,n-1次向右移动。因此路径的总数,就等于从 m+n-2次移动中选择 m-1 次向下移动的方案数,即组合数:
C m-1 m+n-2
=(m+n−2)!/(m−1)!(n−1)!=[(m-n-2)*(m-n-3)*…n]/(m-1)!
class Solution {
public int uniquePaths(int m, int n) {
long ans = 1;
for (int x = n, y = 1; y < m; ++x, ++y) {
ans = ans * x / y;
}
return (int) ans;
}
}