LeetCode刷题笔记(三)--- 斐波那契数列,动态规划相关

文章内容为LeetCode刷题笔记,如发现错误请多多指教

5、从尾到头打印链表:链表相关,多结构混合使用,递归

输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
在这里插入图片描述
从尾到头打印链表,我们可以有多种方法,比如全部把值存储到一个数组中,然后数组逆序,还可以用递归的方式,多写几种方法。
第一种方法是用栈来存储数据,然后将出栈数据保存到数组中,这样就实现了一个逆置

class Solution {
public:
    vector<int> reversePrint(ListNode* head) {
        stack<int> s;
        vector<int> v;
        while(head!=nullptr){
            s.push(head->val);
        }
        while(s.top()!=NULL){
            v.push_back(s.top());
            s.pop();
        }
        return v;
    }
};

第二种方法可以用reverse函数来实现数组的逆置

class Solution {
public:
    vector<int> reversePrint(ListNode* head) {
        vector<int> v;
        while(head!=nullptr){
            v.push_back(head->val);
            head=head->next;
        }
        reverse(v.begin(),v.end());
        return v;
    }
};

第三种方法可以用递归来实现,就是一直递归到链表末尾,然后将值压入数组

class Solution {
public:
    
    void reversePrintHelper(ListNode* head,vector<int> &v){
        if(head==nullptr){
            return;
        }
        reversePrintHelper(head->next,v);
        v.push_back(head->val);
    }
    vector<int> reversePrint(ListNode* head) {
        vector<int> v;
        reversePrintHelper(head,v);
        return v;
    }
};

6、二叉树重建:遍历理解,递归

输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
在这里插入图片描述
二叉树重建我们可以使用递归来解决,前序遍历第一个点必然是根节点,根据这个根节点我们就能把中序遍历结果分成两部分,即左子树和右子树,那么我们就可以根据左子树的元素数量将前序遍历的结果分成两部分,即左子树和右子树;那么左子树和右子树又成了题目描述的那样,根据前序遍历和中序遍历结果进行重建。
在这里插入图片描述

class Solution {
public:

    TreeNode* buildTreehHelper(vector<int> pre,int pre_begin,int pre_end,vector<int> inorder,int inorder_begin,int inorder_end){
        if(pre_begin>pre_end||inorder_begin>inorder_end){
            return nullptr;
        }
        TreeNode *root=new TreeNode(pre[pre_begin]);
        for(int i=inorder_begin;i<=inorder_end;i++){
            if(pre[pre_begin]==inorder[i]){
                root->left=buildTreehHelper(pre,pre_begin+1,i-inorder_begin+pre_begin,inorder,inorder_begin,i-1);
                root->right=buildTreehHelper(pre,i-inorder_begin+pre_begin+1,pre_end,inorder,i+1,inorder_end);
                break;
            }
        }
        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if(preorder.empty()||inorder.empty()) return nullptr;
        return buildTreehHelper(preorder,0,preorder.size()-1,inorder,0,inorder.size()-1);
    }
    
};

7、斐波那契数列:空间复杂度,剪枝重复计算,fib理解

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

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

斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
在这里插入图片描述
关于斐波那契数列的理解,我们有两种解决方式,一种是迭代(dp),另一种是递归,迭代的话首先要定义状态,然后编写状态转移方程,最后确定初始值;另一种方式就是递归了,这个我们用一下剪枝的思想。

class Solution {
public:
    int fib(int n) {
        if(n<2) return n;
        //if(n==1) return 1;
        int num[n+1];
        num[0]=0;
        num[1]=1;
        for(int i=2;i<=n;i++){
            num[i]=(num[i-1]+num[i-2])%1000000007;
        }
        return num[n];
    }
};
//原理代码
class Solution {
public:
    int fib(int n) {
        if(n==0) return 0;
        if(n==1) return 1;
        if(n==2) return 1;
        int first=1;
        int second =1;
        int third =1;
        while(n>2){
            third=(first+second)%1000000007;
            first=second;
            second=third;
            n--;
        }
        return third;
    }
};

递归方案:采用map进行剪枝操作

class Solution {
private:
    unordered_map<int,int> filter;
public:
    int fib(int n) {
        if(n<2){
            return n;
        }
        int ppre=0;
        if(filter.find(n-2)==filter.end()){
            ppre=fib(n-2);
            filter.insert({n-2,ppre});
        }
        else{
            ppre=filter[n-2];
        }
        int pre=0;
        if(filter.find(n-1)==filter.end()){
            pre=fib(n-1);
            filter.insert({n-1,pre});
        }
        else{
            pre=filter[n-1];
        }
        return (ppre+pre)%1000000007;
    }
};

8、青蛙跳台阶问题:场景转化模型,动规,递归

一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
在这里插入图片描述
和上面一样,还是考察动态规划和递归思想

class Solution {
public:
    int numWays(int n) {
        if(n<2) return 1;
        vector<int> dp(n+1);
        dp[0]=1;
        dp[1]=1;
        for(int i=2;i<=n;i++){
            dp[i]=(dp[i-1]+dp[i-2])%1000000007;
        }
        return dp[n];
    }
};

9、矩形覆盖:场景转化模型,特殊情况分析,简单dp

我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

比如n=3时,2*3的矩形块有3种覆盖方法:
在这里插入图片描述

class Solution {
public:
    int rectCover(int number) {
        if(number<2) return number;
        int *dp=new int[number+1];
        dp[0]=1;
        dp[1]=1;
        for(int i=2;i<=number;i++){
            dp[i]=dp[i-1]+dp[i-2];
        }
        int num=dp[number];
        delete dp;
        return num;
    }
};

10、二进制中1的个数:二进制计算

请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。
在这里插入图片描述
位运算
在这里插入图片描述

class Solution {
public:
    int hammingWeight(uint32_t n) {
        int count=0;
        while(n){
            n&=(n-1);
            count ++;
        }
        return count;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值