剑指offer day1

114 阅读1分钟

刷题计划(第1天)

时间:2022.4.16

题数:2

题目类型:栈&动态规划&线性代数

1.斐波那契数列

写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:

F(0) = 0,   F(1) = 1

F(N) = F(N - 1) + F(N - 2), 其中 N > 1.

image.png

第一次尝试了最简单的递归:

class Solution {
public:
    int fib(int n) {
        if(n==0||n==1) return n;
        return fib(n-1)+fib(n-2);
    }
};

image.png

第二次使用循环,避免递归造成的过多浪费(官方解法类似)

class Solution {
public:
    int fib(int n) {
        if(n==0||n==1) return n;
        int a=1,b=0;    //用a和b来模拟0和1
        for(int i=1;i<n;i++){ //注意循环边界条件
            a=a+b;
            b=a-b;
            a%=1000000007;
        }
        return a;
    }
};

image.png

补一个官方解法(1):


class Solution {
public:
    int fib(int n) {
        int MOD = 1000000007;
        if (n < 2) {
            return n;
        }
        int p = 0, q = 0, r = 1;
        for (int i = 2; i <= n; ++i) {
            p = q; 
            q = r; 
            r = (p + q)%MOD;
        }
        return r;
    }
};

第3次用了官方的第二个解法:矩阵快速幂(很难想到)

image.png

class Solution {
public:
    int fib(int n) {
        if(n==0||n==1) return n;
        vector<vector<long>> q{{1,1},{1,0}};
        vector<vector<long>> res=pow(q,n-1);
        return res[0][0];
    }

    vector<vector<long>> pow(vector<vector<long>>& a,int n){
        vector<vector<long>> ret{{1,0},{0,1}};
        while(n>0){
            if(n&1){
                ret=multiply(ret,a);
            }
            n>>=1;
            a = multiply(a, a);
        }
        return ret;
    }
    vector<vector<long>> multiply(vector<vector<long>>& a, vector<vector<long>>& b) {
        vector<vector<long>> c{{0, 0}, {0, 0}};
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 2; j++) {
                c[i][j] = (a[i][0] * b[0][j] + a[i][1] * b[1][j]) %1000000007;
            }
        }
        return c;
    }
};

2.利用两个栈实现队列

用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )

输入与输出示范:(ps.官方的输入输出有点难懂,可以去这道题的评论区的老哥详解)

image.png

这里运用了栈的设计,实现了队列,具体是一个作为进栈,另外一个作为出栈,在两次先进后出后变成了先进先出。

image.png

    private: 
        stack<int> inStack,outStack;
        void ininout(){ //如果在in里面还有元素,则输入进out里面
            while(!inStack.empty()){
                outStack.push(inStack.top());
                inStack.pop();
            }
        }

    
    public:
        CQueue() {
        }
    
        void appendTail(int value) {
            inStack.push(value);
        }
    
        int deleteHead() {
            if(outStack.empty()){
                if(inStack.empty()){
                    return -1;
                }
                ininout();
            }
            int value=outStack.top();
            outStack.pop();
            return value;
        }

};
/**
 * Your CQueue object will be instantiated and called as such:
 * CQueue* obj = new CQueue();
 * obj->appendTail(value);
 * int param_2 = obj->deleteHead();
 */

3.

总结

栈的设计和应用,动态规划已知状态转移方程和结合线性代数,斐波那契数列的求解(非递归)