C语言仿HashMap完成记忆化搜索

至于为何用C语言来开荒算法,我不知道我不知道!!!(无尽的后悔)

但是既然你从标题进来了,那就说明你也准备用C写记忆化搜索,那么我就以下面一题为例,讲解一下C实现记忆化搜索的办法。

这是LeetCode的第70题,爬梯子:

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

示例 1:

输入:n = 2
输出:2
解释:有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶


示例 2:

输入:n = 3
输出:3
解释:有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶
 

提示:

1 <= n <= 45

我的解法:

一般看到这种题目都想先使用递归去做,因为递归最容易理解。首先我们自顶向下分析,当n=6,那么第六级阶梯可能从第五级上来,也可能是第四级。以此类推,图解如下:

C语言仿HashMap完成记忆化搜索_第1张图片

叶子节点只可能是F(2)或者F(1),很明显F(1)和F(2)的值为1和2,那么我们的递推公式就很清楚了,就是C语言仿HashMap完成记忆化搜索_第2张图片

 因此,代码应该不难写出:

int climbStairs(int n){
    if(n == 1) return 1;
    if(n == 2) return 2;
    return climbStairs(n - 1) + climbStairs(n - 2);
}

但是,这个的时间复杂度很高,达到了惊人的O(n²),因此,我们需要进行优化,这里就需要用到我们所需要的记忆化搜索的方法

这里我们需要建立一个键值对,我的想法是,使用数组的下标存储其第几级时的次数,那么就可以少遍历几次,就如下图,红框里的我们算过就不用再算了。

C语言仿HashMap完成记忆化搜索_第3张图片

那么我们就可以这样写出代码。

const int inf = -1;
int *data,flag = 1,Max;
int climbStairs(int n)
{
    if(n <= 2) return n;
    if(flag)
    {
        init(n);
        flag = 0;
    }
    if(data[n] != inf)
        return data[n];
    else{
        int result = climbStairs(n - 1) + climbStairs(n - 2);
        data[n] = result;
        return result;
    }
}
void init(int n)
{
    data = malloc(sizeof(int*)*n);
    memset(data,inf,sizeof(int*)*n);
}

 先给Memory数组赋初值,然后给做过的数组里塞入数据,使得第几级的数据被“记住”。因为次数不可能存在0,那么实现起来就很容易啦!这样子的缺点就是当数据规模很大的时候会占用一大片内存,那么我们还有什么方法呢?

int Memory[45 + 1] = {0,1,2};
int climbStairs(int n){
    if (Memory[n] != 0) return Memory[n];
    return Memory[n] = climbStairs(n - 1) + climbStairs(n - 2), Memory[n];
}

直接预估定长数组即可(要睡觉了摆了,有好想法的可以留言,谢谢)。

你可能感兴趣的:(数据结构与算法,数据结构,算法,c语言,动态规划,散列表)