为了账号安全,请及时绑定邮箱和手机立即绑定

LeetCode-62 划水记录 04

标签:
C++


LeetCode-62 划水记录 04

题目一看;

感觉可以用回溯法 就是从(0.0)开始 走到下一步 再走下一步 走到尽头了 向右边走 到尽头了回去上一个格子 再从上一个格子换一个方向 走 因为只能走2个方向 如果一个格子2个方向都走完了 就又回到上一个

通过这样的办法 可以列出所有路径 并且找到所有的路径数之和。

回溯法递归实现:

代码如下:

//递归版

void uniquePaths2(int m, int n,int H,int L,int *res) 

{

    if (m == H && n == L)

    {

        (*res)++;

        return 0;

    }

    if(m<=H-1)

    uniquePaths2(m + 1, n,H,L,res);

    if(n<=L-1)

    uniquePaths2(m , n+1,H,L,res);

}

int uniquePaths(int m, int n) {

    int res = 0;

    uniquePaths2(1, 1,m,n,&res);

    return res;

}

int main()

{

    int m = 4, n = 4;

    printf("%d\n", uniquePaths(m, n));

    return 0;

}

程序跑出来没问题 用题目提供的样本数据 测试都ok

LeetCode-62 划水记录 04

但是再大一点到 m=20 n=15的时候就超时了 随着m n的增加时间几乎也以几何级的速度增长。程序运行几秒cpu就骂人了。。。

然后我想试试迭代版的时间如何

回溯法迭代版:

//迭代版

struct Point

{

    int x, y;

};

int uniquePaths3(int m,int n)

{

    int x = 0, y = 0,lsx=0,lsy=0;

    int zt[100][100] = { 0 };

    int sum = 0;

    struct Point Yl[100][100] = { 0 };

    while (1)

    {

        if (x >= m || y >= n)//该点超出范围了 返回

        {

            lsx = Yl[x][y].x;

            lsy= Yl[x][y].y;

            x = lsx;    //返回上一点

            y = lsy;

            continue;

        }

        switch (zt[x][y])

        {

        case 0://该点未使用过 默认向下

            zt[x][y]++; //表明已经向下走了一次

            x += 1;

            Yl[x][y].x = x-1;

            Yl[x][y].y= y;

            break;

        case 1:

            zt[x][y]++; //表明已经向下走了一次

            y += 1;

            Yl[x][y].x = x ;

            Yl[x][y].y = y-1;

            break;

        case 2:         //该点下右都走完了 返回上一点

            if (x == 0 && y == 0)

            {

                return sum;

            }

            zt[x][y] = 0;

            lsx = Yl[x][y].x;

            lsy = Yl[x][y].y;

            x = lsx;    //返回上一点

            y = lsy;

            break;

        default:

            break;

        }

        if (x == m - 1 && y == n - 1 && zt[x][y] == 0)

            sum++;

    }

    return sum;

}

int main()

{

    int m = 20, n = 15;

    printf("%d\n", uniquePaths3(m, n));

    //printf("%d\n", uniquePaths(m, n));

    return 0;

}

结果效果跟递归版一样 

。。。然后我就想应该是从0,0 到终点的话会出现很多重复的工作,比如m=10 n=10 从中间5,5到 9,9 点如果有N种走法 那么刚开始 0,0 开始遍历到 5,5的时候 和 1,1遍历到5,5的时候都会从5,5遍历到9,9了。这就重复工作了。可以考虑把5,5到9,9的走法记录下来,然后到5,5的时候就读取这个记录就行了。

但是不能从0,0开始 

应该从9,9终点开始向左边走。

然后走到左边终点的时候 

就返回到上一层的末尾

如此反复到0,0 这样的话在遍历的过程中每个点都可以获取向下和向右的走法数量 两者之和即为该点到终点的走法数;

代码如下:

#include <stdio.h>

/*

0 0 0 0

0 0 0 0

0 0 0 0

0 0 0 0

*/

int uniquePaths2(int m, int n,int h,int l,int **HashMap)

{

    int Sum = 0;

    if (m<0||n<0)//坐标非法

        return 0;

    if (n >= 0 && n <= l-1)//如果还不用切换到上一行

    {

        if (n >= 0 && n < l-1)//可以向右读

        {

            Sum += HashMap[m][n + 1];

        }

        if (m >= 0 && m < h-1)  //可以向下读

        {

            Sum += HashMap[m+1][n];

        }

        if (h-1 == m && l-1 == n) Sum = 1;

        HashMap[m][n] = Sum;

        //切换到上一行

        if (0 == m && n == 0)

        {

            return HashMap[0][0];

        }

        if (n == 0)

        {

            return uniquePaths2(m - 1, l-1,h,l,HashMap);//返回到上一行

        }

        else

            return uniquePaths2(m, n - 1,h,l,HashMap);

    }

    return 0;

}

int uniquePaths(int m, int n) 

{

    int xhbl = 0, xhbl2 = 0;

    //int HashMap[100][100] = { 0 };//记录 leetcode中不能用全局变量 所以只能这样

    int **HashMap = malloc(sizeof(int*) * 100);

    for(xhbl=0;xhbl<100;xhbl++)

        HashMap[xhbl]=malloc(sizeof(int) * 100);

    for (xhbl = 0; xhbl < 100; xhbl++)

    {

        for (xhbl2 = 0; xhbl2 < 100; xhbl2++)

        {

            HashMap[xhbl][xhbl2] = 0;

        }

    }

    HashMap[m-1][n-1] = 1;

    return uniquePaths2(m - 1, n - 1, m, n,HashMap);

}

int main()

{

    printf("%d", uniquePaths(7, 3));

    return 0;

}

提交到leetcode:

LeetCode-62 划水记录 04

没毛病,就是时间太慢了。。

©著作权归作者所有:来自51CTO博客作者hzChan的原创作品,如需转载,请注明出处,否则将追究法律责任


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消