??斗地主捕鱼电竞提现秒到 广告位招租 - 15元/月全站展示
??支付宝搜索579087183领大额红包 ??伍彩集团官网直营彩票
??好待遇→招代理 ??伍彩集团官网直营彩票
??络茄网 广告位招租 - 15元/月全站展示
LeetCode-62 划水记录 04

转载   hzChan   2018-11-11   浏览量:16


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到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
没毛病,就是时间太慢了。。

转载自://blog.51cto.com/3458905/2315491

招聘 不方便扫码就复制添加关注:程序员招聘谷,微信号:jobs1024



C++语言学习(九)——C++标准库简介
C++语言学习(九)——C++标准库简介一、C++标准库简介1、C++标准库简介C++标准库(C++StandardLibrary),是类库和函数的集合。C++编译器厂商根据C++标准委员会官方的ISO规范并将其转化为代码。C++编译器厂商在实现C++标准库过程中必须依赖其不同操作系统所提供的系统调用接口,因此每个平台都有其自己的C++标准库实现。C++标准库的特点如下:A、C++标准库不是C++
C++语言学习(八)——操作符重载
C++语言学习(八)——操作符重载一、操作符重载基础1、操作符重载的语法通过operator关键字可以定义特殊的函数,operator本质是通过函数重载操作符。Typeoperatoroperatorname(constTypep1,constTypep2){Typeret;returnret;}2、友元函数重载操作符可以将操作符重载函数声明为友元函数。#include
C++语言学习(七)——友元
C++语言学习(七)——友元一、友元简介1、友元简介面向对象编程的类的设计机制实现了数据的隐藏与封装,类的成员变量一般定义为私有成员,成员函数一般定义为公有的,是类与外部的通信接口。在实践中,类外的某些函数需要频繁地访问类的成员变量,可以将类外的函数定义为类的友元函数。除了友元函数外,还有友元类,两者统称为友元。友元的作用是提高了程序的运行效率(即减少了类型检查和安全性检查等都需要时间开销),但友
C++语言学习(六)——二阶构造模式
C++语言学习(六)——二阶构造模式一、构造函数的问题构造函数存在的问题:A、构造函数只提供自动初始化成员变量的机会B、不能保证初始化逻辑一定成功,如申请系统资源可能失败C、执行return语句后构造函数立即结束构造函数创建的对象可能是半成品对象,半成品对象是合法的对象,但是程序bug的来源之一。因此实际工程开发过程中使用二阶构造模式。二、二阶构造模式1、二阶构造模式简介由于构造函数存在的潜在问题
C++语言学习(五)——C++语言中的CV限定符错误
C++语言学习(五)——C++语言中的CV限定符错误一、CV限定符错误简介1、CV限定符简介CV限定符即cv-qualifier,C++语言中指const和volatile限定符。通常,C++语言中有两种情况不能使用CV限定符进行限定:A、非成员函数不能使用CV限定B、静态成员函数不能使用CV限定2、CV限定符错误信息简介C++语言中CV限定符错误信息如“cannothavecv-qualifie
C++语言学习(四)——类与对象
C++语言学习(四)——类与对象一、构造函数(constructor)1、构造函数简介C++语言中,构造函数是与类名相同的特殊成员函数。在类对象创建时,自动调用构造函数,完成类对象的初始化。类对象本身是变量,在栈、堆上创建的对象,对象的成员初始化为随机值;在静态存储区创建的对象,对象的成员初始化为0。2、构造函数的定义构造函数声明的语法如下:classname(parameters);没有参数的构
Fishhook原理 源码解读)
用到技术利用dyld相关接口,我们可以注册image装载的监听方法:externvoid_dyld_register_func_for_add_image(void(func)(conststructmach_headermh,intptr_tvmaddr_slide));调用_dyld_register_func_for_add_image注册监听方法后,当前已经装载的image(动态库等)会立
C++反射机制:可变参数模板实现C++反射
1.概要??本文描述一个通过C++可变参数模板实现C++反射机制的方法。该方法非常实用,在Nebula高性能网络框架中大量应用,实现了非常强大的动态加载动态创建功能。Nebula框架在coding.net的仓库地址。??C++11的新特性--可变模版参数(variadictemplates)是C++11新增的最强大的特性之一,它对参数进行了高度泛化,它能表示
MachOView源码 AppController.mm
//AppController.h/**AppController.h*MachOView**Createdbypsaghelyion15/06/2010.**/#import@classMVPreferenceController;@interfaceMVAppController:NSObject
火车订票系统源码笔记c++
火车订票系统源码笔记c++