数组左上方到右下方的路径

小兔子在一个M*N的方格的左上方,家在方格的右下方,其中部分方格有蛇,小兔子不能走有蛇的方格。小兔子每一步只能向右或向下,问小兔子回家有多少条路径?

1首先想到递归:

#define M (5)

#define N (4)

int map[M][N]={{0,0,0,1},

{0,0,1,0},

{0,0,0,0},

{0,0,1,0},

{0,0,0,0}

};

int getPathNumBydigui(int row, int col){

int pathNum = 0;

if(row==0 && col==0) return 1;

if(map[row][col] == 1) return 0;

if(IsValidPos(row-1, col)){

pathNum += getPathNumBydigui(row-1, col);

}

if(IsValidPos(row, col-1)){

pathNum += getPathNumBydigui(row, col-1);

}

return pathNum;

}

但我们知道递归的时间和空间复杂度都是指数级的,并不可取

因此采用动态规划的方法,此时的时间复杂度和空间复杂度都是M*N

bool IsValidPos(int row, int col){

if((row>=0&&row<M) && (col>=0&&col<N) && (map[row][col] != 1)) return true;

return false;

}

int getPathNumBydynamic(int row, int col){

int pathRecord[M][N] = {{1}};

for(int i=0; i<M; i++){

for(int j=0; j<N; j++){

if(IsValidPos(i-1, j)){

pathRecord[i][j] += pathRecord[i-1][j];

}

if(IsValidPos(i, j-1)){

pathRecord[i][j] += pathRecord[i][j-1];

}

}

}

return pathRecord[row][col];

}

2空间复杂度在动态规划的基础上还可以继续优化。我们注意到上面的动态规划实际记录了小兔子到任意点的路径条数。实际上我们只需要到右下方的结果,因此把二维数组pathRecord降为一维,每次只更改一行的动态规划数据

int getPathNumBydynamicWithNSpace( int col){ //不妨假设N<M,即此函数空间复杂度为O(N),此时仅保存了最后一行 各个格子的路径条数

int pathRecord[N] = {1};

for(int i=0; i<M; i++){

if(map[i][0] == 1){

pathRecord[0] = 0;

}

for(int j=1; j<N; j++){

if(map[i][j] != 1){

pathRecord[j] += pathRecord[j-1];

}

else{

pathRecord[j] = 0;

}

}

}

return pathRecord[col];

}

3,测试用例:map:

{{0,0,0,1},

{0,0,1,0},

{0,1,0,0},

{0,0,1,0},

{0,0,0,0}

};

到右下方的路径均为2

{{0,0,0,1},

{0,0,1,0},

{0,0,0,0},

{0,0,1,0},

{0,0,0,0}

};

到右下方的路径均为8

{{0,0,0,0},

{0,0,0,0},

{0,0,0,0},

{0,0,0,0},

{0,0,0,0}

};

到右下方的路径均为35

4,设计一个函数返回的是所有的路径,而不是路径的数目

考虑使用递归回溯的算法,每走一步都将坐标记录进vector中,如果当前坐标为最右下方,则保存下这条路径,在递归函数退出时需要将当前坐标从vector中拿出

vector<pair<int, int>> onePath;

vector<vector<pair<int, int>>> allPath;

void recordAllPath(int row, int col){

pair<int,int> point = {row,col};

onePath.push_back(point);

if(row == M-1 && col == N-1){

allPath.push_back(onePath);

onePath.pop_back();

return;

}

if(IsValidPos(row+1, col)){

recordAllPath(row+1, col);

}

if(IsValidPos(row, col+1)){

recordAllPath(row, col+1);

}

onePath.pop_back();

}

5,如果兔子不是只能向右或者向下,而是上下左右所有的方向都可以走,只是一个格子最多只能走一次,那么如何记录所有的路径。

这个问题与问题4类似,只是需要加一个该格子是否已经走过的判断,并且在下一步递归时,需要判断4个方向。

bool IsValidPosII(int row, int col){

if((row>=0&&row<M) && (col>=0&&col<N) && (map[row][col] != 1) && !visited[row][col]) return true;

return false;

}

void recordAllPathII(int row, int col){

pair<int,int> point = {row,col};

onePath.push_back(point);

visited[row][col] = true;

if(row == M-1 && col == N-1){

allPath.push_back(onePath);

onePath.pop_back();

visited[row][col] = false;

return;

}

if(IsValidPosII(row+1, col)){

recordAllPathII(row+1, col);

}

if(IsValidPosII(row-1, col)){

recordAllPathII(row-1, col);

}

if(IsValidPosII(row, col+1)){

recordAllPathII(row, col+1);

}

if(IsValidPosII(row, col-1)){

recordAllPathII(row, col-1);

}

onePath.pop_back();

visited[row][col] = false;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值