重建二叉树、打印链表、青蛙跳台阶

面试题06. 从尾到头打印链表

题目描述:

输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。

输入:head = [1,3,2]
输出:[2,3,1]
限制:
0 <= 链表长度 <= 10000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路:

采用一个栈, 实现逆序

代码

    vector<int> reversePrint(ListNode* head) {
        auto ptr = head;
        vector<int> lst;
        stack<int> sta;
        // 将链表内容,输入栈中
        while( ptr != NULL){
            sta.push(ptr->val);
            ptr = ptr->next;
        }
        // 逆序输出到向量中
        while(!(sta.empty())){
            lst.push_back(sta.top());
            sta.pop();
        }
        return lst;
    }

面试题07. 重建二叉树

题目描述

输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:

3
/
9 20
/
15 7

思路

对于二叉树的问题,常常会采用递归,应为二叉树本身就是递归定义。而递归和二叉树对于初学者来说确实很有难度,这道题我查看题解很长时间,才略懂。

在这里插入图片描述
图片来源:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/solution/er-cha-shu-de-qian-xu-bian-li-fen-zhi-si-xiang-by-/

特点:

  • 根据前序遍历可以,前序遍历的第一个元素为一个根结点
  • 根据中序遍历序列中,中间的根结点可以将整个序列划分成左子树序列和右子树序列
  • 根据中序遍历中左、右子树序列的数目,可以推断出在前序遍历序列中的左、右子树的边界。如图所示。

代码

	// 注意 迭代器的区间是左闭右开
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        return recurisonBuild(preorder.begin(), preorder.end(), inorder.begin(), inorder.end());
    }

    TreeNode* recurisonBuild(vector<int>::iterator preBegin, vector<int>::iterator preEnd,
                            vector<int>::iterator inBegin, vector<int>::iterator inEnd)
    {
        if(inBegin==inEnd) return NULL;
        auto root = find(inBegin, inEnd, *preBegin);
        TreeNode* cur = new TreeNode(*preBegin);
        cur->left = recurisonBuild(preBegin+1, preBegin+1+(root-inBegin), inBegin, root);
        cur->right = recurisonBuild(preBegin+1+(root-inBegin), preEnd, root+1, inEnd);
        return cur;
    }

面试题09. 用两个栈实现队列

题目描述

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/yong-liang-ge-zhan-shi-xian-dui-lie-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路:

一个栈可以用于逆序输出元素,利用这样的特点可以实现队列(采用两个栈)
一个栈s1用于输入元素,一个栈用于逆序输出元素
输入直接存入栈s1,输出时首先判断s2是否存在元素,如果有则直接弹出其元素(因为该元素本身具有先入先出的顺序),否则将s1中所有元素导入s2中,再进行弹出一元素
###代码

    // s1用于入栈,s2用于出栈
    stack<int> s1, s2;

    void appendTail(int value) {
        s1.push(value);
    }
    
    int deleteHead() {

        if(s2.empty()){
            if(s1.empty()) return -1;  // 两个栈均为空,表面该队列为空
            else{
                do{
                    s2.push(s1.top());
                    s1.pop();
                }while(!s1.empty());
            }
        }
        int res = s2.top();
        s2.pop();
        return res;
    }

面试题10- I. 斐波那契数列

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

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

斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

思路

经典题目,学习递归的常用例子。在leetcode中,直接采用递归法会超时。
这里采用优化的动态规划方法或者说直接套用递推公式。给定sum、a、b三个辅助变量

代码

    int fib(int n) {
        // 边界条件
        if(n==0||n==1) return n;

        int sum = 0;
        int a = 0, b = 1;
        for(int i = 2; i < n+1;i++){
            sum = (a+b)%1000000007;        // 递推公式
            a = b;  // 更新前数
            b = sum;  // 更新后数
        }
        return sum;
    }

面试题10- II. 青蛙跳台阶问题

题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

示例 1:
输入:n = 2
输出:2
示例 2:
输入:n = 7
输出:21
提示:
0 <= n <= 100
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/qing-wa-tiao-tai-jie-wen-ti-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

重要的是打开思路,想到递归策略。
最后一步分成两种情况,一步或者两步

  1. 假设只需最后一步抵达第N个台阶,此时的路线数为 f ( n − 1 ) f(n-1) f(n1)
  2. 假设需要两步抵达第N个台阶,此时的路线数为 f ( n − 2 ) f(n-2) f(n2)

所以 f ( n ) = f ( n − 1 ) + f ( n − 2 ) f(n) = f(n-1)+f(n-2) f(n)=f(n1)+f(n2),与Fibonacci数列的递推公式一样,区别在于初始条件。

代码

    int numWays(int n) {
        // 边界情况
        if(n==0||n==1)  return 1;

        int sum=0;
        int a=1, b=1;
        for(int i=2; i <= n; i++){
            sum = (a+b)%1000000007;
            a = b;
            b = sum;
        }
        return sum;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值