《程序員代碼面試指南--IT名企算法與數據結構題目最優解》 左程雲 著
機器人到達指定位置方法數
【題目】
假設有排成一行的N個位置,記為1~N,N一定大於或等於2。開始時機器人在其中的M位置上(M一定是1~N中的一個),
機器人可以往左走或者往右走,如果機器人來到1位置,那么下一步只能往右來到2位置;
如果機器人來到N位置,那么下一步只能往左來到N-1位置。
規定,機器人必須走K步,最終能來到P位置(P也一定是1~N中的一個)的方法有多少種。
給定4個參數N、M、K、P,返回方法數。
【要求】
時間復雜度為O(N*K)
#include <algorithm> #include <iostream> #include <stack> #include <vector> #include <exception> using namespace std;
方法1:暴力遞歸求解(暴力遞歸建模比較困難(至少對於我來說是如此))
//////////////////////////////////////////暴力遞歸求解 //N:位置為1~N,固定參數 //cur:當前在cur位置,可變參數 //rest:還剩res步沒有走,可變參數 //P:最終目標位置P,固定參數 //只能在1~N這些位置上移動,當前在cur位置,走完rest步之后,停在P位置的方法數作為返回值返回 // int walk(int N, int cur, int rest, int P) { //如果沒有剩余步數了,當前的cur位置就是最后的位置 //如果最后的位置停在P上,那么之前做的移動是有效的 //如果最后的位置沒有停在P上,那么之前做的移動是無效的 if (rest == 0) { return cur == P ? 1 : 0; } //如果還有rest步要走,而當前的cur位置在1位置上,那么當前這步只能從1走向2 //后續的過程就是原來到2位置上,還剩rest-1步要走 if (cur == 1) { return walk(N, 2, rest - 1, P); } //如果還有rest步要走,而當前的cur位置在N位置上,那么當前這步只能從N走向N-1 //后續的過程就是來到N-1位置上,還剩rest-1步要走 if (cur == N) { return walk(N, N - 1, rest - 1, P); } //如果還有rest步要走,而當前的cur位置在中間位置上,那么可以向左走,也可以向右走 // return walk(N, cur - 1, rest - 1, P) + walk(N, cur + 1, rest - 1, P); } int ways1(int N, int M, int K, int P) { //參數無效直接返回 if (N < 2 || K < 1 || M<1 || M>N || P<1 || P>N) { return 0; } //總共N個位置,從M點出發,還剩K步,返回最終能達到P的方法數 return walk(N, M, K, P); }
方法2:通過暴力遞歸,分析模型,然后用循環的方法求解
/////////////////////////////////////遞歸思路分析,循環方法解決 int ways2(int N, int M, int K, int P) { //參數無效直接返回0 if (N < 2 || K < 1 || M<1 || M>N || P<1 || P>N) { return 0; } int iResult = 0; int** dp = new int*[K + 1]; for (int i = 0; i < K + 1; i++) { dp[i] = new int[N + 1]; } //給第1行賦值,如果走0步,只有在p點才是有效的,其他位置無效,為0 for (int i = 0; i < N + 1; i++) { if (i != P) { dp[0][i] = 0; } else { dp[0][i] = 1; } } for (int j = 0; j < K + 1; j++) { dp[j][0] = 0; } for (int i = 1; i < K + 1; i++) { for (int j = 1; j < N + 1; j++) { if (j == 1) { dp[i][j] = dp[i-1][2]; } else if (j == N) { dp[i][j] = dp[i - 1][N - 1]; } else { dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j + 1]; } } } /////打印這個輔助數組 printf("dp[][]------------way2----------------start\r\n"); for (int i = 0; i < K + 1; i++) { for (int j = 0; j < N + 1; j++) { printf("%5d,", dp[i][j]); } printf("\r\n"); } printf("dp[][]-------------way2---------------end\r\n"); iResult = dp[K][M]; for (int i = 0; i < K + 1; i++) { delete[] dp[i]; } delete[] dp; return iResult; }
方法3:在方法2的基礎上,對申請的內存空間做優化。只申請一個一維的數組空間。
///壓縮到一維數組 int ways3(int N, int M, int K, int P) { //參數無效直接返回0 if (N < 2 || K < 1 || M<1 || M>N || P<1 || P>N) { return 0; } int iResult = 0; int* dp = new int[N + 1]; //給第1行賦值,如果走0步,只有在p點才是有效的,其他位置無效,為0 for (int i = 0; i < N + 1; i++) { if (i != P) { dp[i] = 0; } else { dp[i] = 1; } } for (int i = 1; i < K + 1; i++) { int LeftUp = dp[1]; for (int j = 1; j < N + 1; j++) { int tempLeft = dp[j]; if (j == 1) { dp[j] = dp[j+1]; } else if (j == N) { dp[j] = LeftUp; } else { dp[j] = LeftUp + dp[j + 1]; } LeftUp = tempLeft; ///保存舊的的左值 } } iResult = dp[M]; delete[] dp; return iResult; }
測試用例很重要。要用若干個測試用例去覆蓋可能的各種情況。增強程序健壯性。
//==================測試用例==================== void test1() { //5,2,3,3, //7,4,9,5 int N = 0; int M = 0; int K = 0; int P = 0; cout << "Test1---------------------------------" << endl; N = 7; M = 4; K = 9; P = 5; //cout << "way1:" << ways1(N, M, K, P) << endl;; cout << "way2:" << ways2(N, M, K, P) << endl;; cout << "way3:" << ways3(N, M, K, P) << endl << endl;;; } void test2() { //5,2,3,3, //7,4,9,5 int N = 0; int M = 0; int K = 0; int P = 0; cout << "Test2---------------------------------" << endl; N = 7; M = 2; K = 13; P = 5; //cout << "way1:" << ways1(N, M, K, P) << endl;; cout << "way2:" << ways2(N, M, K, P) << endl;; cout << "way3:" << ways3(N, M, K, P) << endl << endl;; } void test3() { int N = 0; int M = 0; int K = 0; int P = 0; cout << "Test3---------------------------------" << endl; N = 5; M = 2; K = 3; P = 3; //cout << "way1:" << ways1(N, M, K, P) << endl;; cout << "way2:" << ways2(N, M, K, P) << endl;; cout << "way3:" << ways3(N, M, K, P) << endl << endl;; } int main() { test1(); test2(); test3(); cout << endl; system("pause"); return 0; }
這里展示部分的運行結果:
Test3--------------------------------- dp[][]------------way2----------------start 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 2, 0, 1, 0, 0, 3, 0, 3, 0, dp[][]-------------way2---------------end way2:3 way3:3