关于k阶裴波那契序列的两种解法

在学校的anyview的时候,遇到了这个题:

 

【题目】已知k阶裴波那契序列的定义为
f(0)=0, f(1)=0, ..., f(k-2)=0, f(k-1)=1;
f(n)=f(n-1)+f(n-2)+...+f(n-k), n=k,k+1,...
试编写求k阶裴波那契序列的第m项值的函数算法,
k和m均以值调用的形式在函数参数表中出现。

要求实现下列函数:
Status Fibonacci(int k, int m, int &f);
/* 如果能求得k阶斐波那契序列的第m项的值f,则返回OK;*/
/* 否则(比如,参数k和m不合理)返回ERROR */

 

然后我自己想到的是用递归来做,一开始我用的是纯递归,大概思路就是n大于k-1的部分,都用递归解除,然后再把递归的结果累加,最后得到fn。然后提交的时候,虽然出来几个都是right,但速度极慢,可以说是很难跑完。

后来一个大佬帮我看了后,说这里递归好多次,太耗内存了,就好多结果重复算。(因为是累加的时候有很多重复)然后,就改装了一下,弄了个数组来存中间递归的数,来看代码:

/**********
【题目】已知k阶裴波那契序列的定义为
    f(0)=0, f(1)=0, ..., f(k-2)=0, f(k-1)=1;
    f(n)=f(n-1)+f(n-2)+...+f(n-k), n=k,k+1,...
试编写求k阶裴波那契序列的第m项值的函数算法,
k和m均以值调用的形式在函数参数表中出现。
**********/
int a[1000];       //数列是拿来记住结果的,不然我这种递归每一次都会很多重复
int beforek = 0;
void addCount(int m)
{
    for(int i=0;i<=m+5;i++)
        a[i]=0;

}

Status Fibonacci(int k, int m, int &f) 
/* 求k阶斐波那契序列的第m项的值f */
{    
    
    if(k<=1||m<0) {
        f = 0;       
        return ERROR;
    }        
    if(beforek==0||beforek!=k) {
          beforek=k;
          memset(a,0,sizeof(int)*(m+5));    
    }
    if(a[m]!=0) {f=a[m];return OK;}
    if(m<k){
        if(m==(k-1)){
            f = 1;
            a[m] = f;
            return OK;
        } else {
            f = 0;
            a[m] = f; 
            return OK;
        }
    }
    else {//m>=k
        int result = 0;
        int bound = m-k;
        m--;          
        while(m>=bound) {    
            int temp = 0 ;
            Fibonacci(k,m,temp);
            a[m] = temp;
            result = result + temp;
            m--;
        }
        f = result;      
        return OK;
    }    
}

 

后面有做到这个题,不过是要求用循环队列来做,然后就换个思路思考,

观察发现fn前面k-1个数的取值是0/1,然后fn的值当n大于k-1的时候,
它的值就会等于fn-1还有后面的一共k-1个数的和,所以我们让队列保持有k-1个
数,然后不断插入f,f的值是队列中k-1个数的和,插入后又踢掉一个,直到尾
巴指到n-1,然后再把这个队列末尾那个返回就行了,

看代码:

本题的循环队列的类型定义如下:
typedef struct {
  ElemType *base; // 存储空间的基址
  int front;      // 队头位标
  int rear;       // 队尾位标,指示队尾元素的下一位置
  int maxSize;    // 最大长度
} SqQueue;
**********/

/*思路:观察发现fn前面k-1个数的取值是0/1,然后fn的值当n大于k-1的时候,
它的值就会等于fn-1还有后面的一共k-1个数的和,所以我们让队列保持有k-1个
数,然后不断插入f,f的值是队列中k-1个数的和,插入后又踢掉一个,直到尾
巴指到n-1*/


int InitSqQueue(SqQueue &Q,int n) {     //初始化,建立空队列
    Q.base = (ElemType *)malloc(sizeof(ElemType)*(n+1));
    if(Q.base==NULL) return 0;
    Q.front = 0;
    Q.rear = 0;
    Q.maxSize = n;
    return 1;
}

int EnSqQueue(SqQueue &Q,ElemType e) {
     if(  (Q.rear+1)%Q.maxSize==Q.front  ) {
        return 0;
     } else {
        Q.base[Q.rear] = e;
        Q.rear = (Q.rear+1)%Q.maxSize;
        return 1;
     }
}

int DeSqQueue(SqQueue &Q,ElemType &e) {
    if(Q.rear==Q.front) {
        return 0;
    } else {
        e = Q.base[Q.front];
        Q.front = (Q.front+1)%Q.maxSize;
        return 1;
    }
}

long Fib(int k, int n)
/* 求k阶斐波那契序列的第n+1项fn */
{
    if(n<=k-2)return 0;
    if(n==k-1)return 1;
    /*下面的情况n一定是大于k-1的*/
    SqQueue Q;
    InitSqQueue(Q,n+k);//maxSize应该是无所谓的
    int f,i,e;
    for(i = 0; i <= k-1 ; i ++) { //结束后循环队列里应该有k个元素
        if(i<=k-2) {
            f = 0;
        } else if(i==(k-1)) {
            f = 1;
        }
        EnSqQueue(Q,f);
    }
    int theRear = k-1;//此时的rear元素是k-1
    while(theRear <= n-1) {
        for(i = Q.front, f = 0; i < Q.rear; i = (i+1)%Q.maxSize) {
            f = f + Q.base[i];      //求出的f是队列中k-1个元素的和
        }
        EnSqQueue(Q,f);//f入队
        DeSqQueue(Q,e);//出一个队,保持队列中有k-1个元素
        theRear++;
    }
    return Q.base[Q.rear-1];//最后一个就是fn的值
}

 

posted @ 2017-10-30 20:40  汪神  阅读(883)  评论(0编辑  收藏  举报