機器人走路問題
一個機器人可以在1~N上行走,每一步可以向前或向後走,給定起點S > 1,終點 < N,每一次行走K步,機器人從S走到E一共有多少種方法。
暴力遞歸
暴力遞歸存在大量重複的遞歸過程。可以用空間換取時間,記錄可能出現的重複解,之後不需要遞歸展開直接拿到之前算過的值。即,記憶化搜索。時間複雜度O(2^K)
1 public static int walkMethod(int N, int start, int end, int K){ 2 return process(N,start,end,K); 3 } 4 /** 5 * 6 * @param N 一共有N個位置 7 * @param cur 當前在哪個位置 8 * @param end 最終的目標位置 9 * @param restK 可以走幾步 10 * @return 11 */ 12 private static int process(int N, int cur, int end, int restK) { 13 if(restK == 0){//不能繼續走了 14 return cur == end? 1:0;//找到1種 或者 沒找到 15 } 16 if(cur == 1){//只有一種走法 向右走 17 return process(N,2,end,restK-1); 18 } 19 if(cur == N){//只有一種走法 向左走 20 return process(N,N-1,end,restK-1); 21 } 22 //可以向左走 或者 向右走 23 return process(N,cur-1,end,restK-1) + 24 process(N,cur+1,end,restK-1); 25 }
記憶化搜索
時間複雜度O(K*N)
1 public static int walkMethod2(int N, int start, int end, int K) { 2 int dp[][] = new int[K + 1][N + 1]; 3 for (int i = 1; i <= K; i++) { 4 for (int j = 0; j <= N; j++) { 5 dp[i][j] = -1; 6 } 7 } 8 return process2(N, start, end, K, dp); 9 } 10 11 private static int process2(int N, int cur, int end, int restK, int[][] dp) { 12 if (dp[restK][cur] != -1) { 13 return dp[restK][cur];//之前計算過 直接return 14 } 15 if (restK == 0) { 16 dp[restK][cur] = cur == end ? 1 : 0; 17 return dp[restK][cur]; 18 } 19 if (cur == 1) { 20 dp[restK][cur] = process2(N, cur + 1, end, restK - 1, dp); 21 }else if (cur == N) { 22 dp[restK][cur] = process2(N, cur - 1, end, restK - 1, dp); 23 }else{ 24 dp[restK][cur] = process2(N, cur - 1, end, restK - 1, dp) + process2(N, cur + 1, end, restK - 1, dp); 25 } 26 return dp[restK][cur]; 27 }
嚴格表結構
表的含義是:restK步走到cur有f(restK, cur)種方法
從開始 2 走到 終點 4 【f(0,4) = 1 f(0,else) = 0】走4步有多少種方法
dp(restK, cur) = dp(restK-1, cur-1) 【cur == N】
dp(restK, cur) = dp(restK+1, cur-1) 【cur == 1】
dp(restK, cur) = dp(restK-1, cur-1) + dp(restK+1, cur-1) 【1<cur<N】
return dp(K, start)