力扣剑指Offer(二)
1、重建二叉树(递归)
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
   3
   / \
  9  20
    /  \
   15   7
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        return recursion(0,0,inorder.size()-1,preorder,inorder);
    }
private:
    TreeNode* recursion(int root,int left,int right,vector<int>& preorder, vector<int>& inorder){
        if(left>right)
            return nullptr;
        TreeNode* p=new TreeNode(preorder[root]);
        int j;
        for(int i=left;i<=right;i++){
            if(inorder[i]==preorder[root]){
                j=i;
                break;
            }
        }
        p->left=recursion(root+1,left,j-1,preorder,inorder);
        p->right=recursion(root+j-left+1,j+1,right,preorder,inorder);
        return p;
    }
};
优化:
构造中序序列中值和下标的哈希映射,方便递归时寻找
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        this->preorder=preorder;
        for(int i=0;i<inorder.size();i++){
            mp[inorder[i]]=i;
        }
        return recursion(0,0,inorder.size()-1);
    }
private:
    vector<int> preorder;
    unordered_map<int,int> mp;
    TreeNode* recursion(int root,int left,int right){
        if(left>right)
            return nullptr;
        TreeNode* p=new TreeNode(preorder[root]);
        int j=mp[preorder[root]];
        p->left=recursion(root+1,left,j-1);
        p->right=recursion(root+j-left+1,j+1,right);
        return p;
    }
};
2、斐波那契数列
写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:
F(0) = 0,   F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
输入:n = 2
输出:1
示例 2:
输入:n = 5
输出:5
提示:
- 0 <= n <= 100
方法一:动态规划
class Solution {
public:
    int fib(int n) {
        vector<int> dp(n+1,0);
        if(n<2)
            return n;
        dp[1]=1;
        for(int i=2;i<=n;i++){
            dp[i]=(dp[i-1]+dp[i-2])%1000000007;
        }
        return dp[n];
    }
};
优化:不用开数组
class Solution {
public:
    int fib(int n) {
        if(n<2)
            return n;
        int a=0;
        int b=1;
        int c;
        for(int i=2;i<=n;i++){
            c=(a+b)%1000000007;
            a=b;
            b=c;
        }
        return c;
    }
};
方法二:递归(超时)
class Solution {
public:
    int fib(int n) {
        if(n==0)
            return 0;
        if(n==1)
            return 1;
        return (fib(n-1)+fib(n-2))%1000000007;
    }
};
优化:记忆化递归法
class Solution {
public:
    int b[110];
    int fib(int n) {
        if(n<=1)return n;
        if(!b[n])return b[n]=(fib(n-1)+fib(n-2))%1000000007;
        return b[n];
    }
};
总结
- 
递归法: - 
原理: 把 f(n)问题的计算拆分成f(n−1)和f(n−2)两个子问题的计算,并递归,以f(0)和 f(1)为终止条件。 
- 
缺点: 大量重复的递归计算,例如f(n)和f(n−1)两者向下递归需要各自计算f(n−2)的值。 
 
- 
- 
记忆化递归法: - 
原理: 在递归法的基础上,新建一个长度为n的数组,用于在递归时存储f(0)至f(n)的数字值,重复遇到某数字则直接从数组取用,避免了重复的递归计算。 
- 
缺点: 记忆化存储需要使用 O(N)的额外空间。 
 
- 
- 
动态规划: - 原理: 以斐波那契数列性质f(n+1)=f(n)+f(n-1)f(n+1)=f(n)+f(n−1)为转移方程。
 
从计算效率、空间复杂度上看,动态规划是本题的最佳解法。
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号