演算法練習帖--23--不同路徑(Java)
阿新 • • 發佈:2020-12-14
不同路徑
一個機器人位於一個 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;
}
}