面试算法之递归和循环

 

       在解决问题时如果我们需要多次重复的计算同一个问题,我们可以选择递归或者循环,递归是函数内部调用函数自身,直到一个终止条件,而循环是通过设置初始条件和终止条件,在一个范围内重复运算。比如求1+2+3+....+n;

递归算法如下:

int add_1toN_recursive(int n)
{
        return n <= 1 ? 1 : n + add_1toN_recursive(n-1);
}

循环算法如下;

int add_1toN_iterative(int n)
{
        int value = 0;
        int i = 0;
        for (i = 1; i <= n; ++i)
                value+=i;
        return value;
}

        我们可以看出,递归代码很简洁明了,但是递归也有自身的致命缺点,递归由于是调用函数自身,需要进行压栈,保存参数、返回地址和临时变量,而且很多计算都是重复运算的,给性能带来很大的负面影响,如果调用层级太多,会导致栈溢出,出现segfault。

       对于经典的斐波拉切数列,我们从数据结构书上可以很快写出:

int fibonacci(int n)

{

    if (n <= 0)

        return 0;

    if (n == 1)

        return 1;

    return fibonacci(n-1) + fibonacci(n-2);

}

但是如果n数值很大的话,速度慢是一回事,有时候会导致栈溢出,segfault出现,但是在树的前序、中序和后续遍历中,递归的实现却是比循环简洁好看多。

循环算法如下:

int fibonacci1(int n)

{

        if (n <= 0)

                return 0;

        int f0 = 0;

        int f1 = 1;

        int fn = 0;

        int i;

        for (i = 2; i <= n; ++i)

        {

            fn = f0+f1;

            f0 = f1;

            f1 = fn;

        }

        return fn;

}

        面试官又可能衍生出另外一种问法:一只青蛙跳台阶,一次可以跳1级,一次也可以跳2级,请问青蛙跳N级台阶有多少种跳法?

        很简单,我们考虑简单的情况,假如只有1级台阶,青蛙显然只有一种跳法,如果有2级台阶,那就有两种跳法,一种是一次跳1级,跳两次;另一种是一次直接跳2级,那我们返回到一般情况讨论,把n级台阶当成n的函数,记为f(n),当n>2时,第一次跳就有两种不同选择,一是第一次只跳1级,此时跳法数目等于后面剩下的n-1级台阶的跳法数目,记为f(n-1);另外一种是第一次跳2级,此时跳法数目等于后面剩下的n-2级台阶的跳法数目,记为f(n-2),由此我们推算出n级台阶的不同跳法总数是f(n)=f(n-1)+f(n-2),可以看出这个就是斐波拉切数列。

猜你喜欢

转载自blog.csdn.net/yangrendong/article/details/89218151