1. 程式人生 > 其它 >演算法練習帖--23--不同路徑(Java)

演算法練習帖--23--不同路徑(Java)

技術標籤:演算法演算法動態規劃leetcodejava

不同路徑

一個機器人位於一個 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;
    }
}