剑指offer面试高频题系列题解分析

本文详细介绍了如何使用递归方法根据前序和中序遍历重建二叉树,以及如何利用两个栈实现队列操作。此外,还探讨了经典的斐波那契数列问题及其在跳跃游戏中应用的解题思路,包括基础版本和扩展版本。这些算法展示了在解决计算机科学问题时的逻辑思考和递归处理能力。
摘要由CSDN通过智能技术生成

剑指offer高频题系列题解分析

4.重建二叉树

给定某二叉树的前序遍历和中序遍历,请重建出该二叉树并返回它的头结点。

例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如下图所示。

img

提示:

1.0 <= pre.length <= 2000

2.vin.length == pre.length

3.-10000 <= pre[i], vin[i] <= 10000

4.pre 和 vin 均无重复元素

5.vin出现的元素均出现在 pre里

6.只需要返回根结点,系统会自动输出整颗树做答案对比

输入:

[1,2,4,7,3,5,6,8],[4,7,2,1,5,3,8,6]

复制

返回值:

{1,2,3,4,#,5,6,#,7,#,#,8}

复制

说明:

返回根节点,系统会输出整颗二叉树对比结果  

解题思维:

递归构建二叉树

根据中序遍历和前序遍历可以确定二叉树,具体过程为:

  1. 根据前序序列第一个结点确定根结点
  2. 根据根结点在中序序列中的位置分割出左右两个子序列
  3. 对左子树和右子树分别递归使用同样的方法继续分解

例如:
前序序列{1,2,4,7,3,5,6,8} = pre
中序序列{4,7,2,1,5,3,8,6} = in

  1. 根据当前前序序列的第一个结点确定根结点,为 1
  2. 找到 1 在中序遍历序列中的位置,为 in[3]
  3. 切割左右子树,则 in[3] 前面的为左子树, in[3] 后面的为右子树
  4. 则切割后的左子树前序序列为:{2,4,7},切割后的左子树中序序列为:{4,7,2};切割后的右子树前序序列为:{3,5,6,8},切割后的右子树中序序列为:{5,3,8,6}
  5. 对子树分别使用同样的方法分解
import java.util.*;
public class Solution{
    public TreeNode reConstructBinaryTree(int [] pre,int [] in){
        if(pre.length == 0|| in.length == 0){
            return null;
        }
        TreeNode root = new TreeNode(pre[0]);
          // 在中序中找到前序的根
        for(int i=0; i<in.lentgth; i++){
            if(in[i]==pre[0]){
                root.left = reConstructBinaryTree(Arrays.copyofRange(pre,1,i+1),Arrays.copyofRange(in,0,i));
                 root.right = reConstructBinaryTree(Arrays.copyofRange(pre,i+1,pre.length),Arrays.copyofRange(in,i+1,in.length));
                break;
                
            }
        }
        return root;
    }
}


5.用两个栈实现队列

用两个栈来实现一个队列,完成n次在队列尾部插入整数(push)和在队列头部删除整数(pop)的功能。 队列中的元素为int类型。保证操作合法,即保证pop操作时队列内已有元素。

示例1

输入:

["PSH1","PSH2","POP","POP"]

复制

返回值:

1,2

复制

说明:

"PSH1":代表将1插入队列尾部
"PSH2":代表将2插入队列尾部
"POP“:代表删除一个元素,先进先出=>返回1
"POP“:代表删除一个元素,先进先出=>返回2 

解题思维

思路:

  • 栈A用来作入队列
  • 栈B用来出队列,当栈B为空时,栈A全部出栈到栈B,栈B再出栈(即出队列)
import java.util.*;

public classSoution{
    Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();
    
    public void push(int node){
        stack1.push(node);
    }
    
    public int pop(){
        if(stack2.size()<=0){
            while(stack.size()!=0){
                stack2.push(stack1.pop());
            }
        }
        return stack2.pop();
    }
}

7 .斐波那契数列

大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0,第1项是1)。

F(n)=F(n - 1)+F(n - 2)

public class Solution{
    public int Fibonacci(int n){
        if(n<=1){
            return n;
        }
        return Fibonacci(n-1) + Fibonacci(n-2);
    }
}

8.跳台阶n

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

解题思路:

对于第n个台阶来说,只能从n-1或者n-2的台阶跳上来,所以
F(n) = F(n-1) + F(n-2)
斐波拉契数序列,初始条件
n=1:只能一种方法
n=2:两种
递归一下就好了

public class Solution {
    public int jumpFloor(int target) {
        if(target <= 0)
            return 0;
        else if(target == 1)
            return 1;
        else if(target == 2)
            return 2;
        else
            return jumpFloor(target-1) + jumpFloor(target-2);
    
    }
}

9 跳台阶扩展问题

一只青蛙一次可以跳上**1级台阶,也可以跳上2级……它也可以跳上n级。**求该青蛙跳上一个n级的台阶(n为正整数)总共有多少种跳法。

解题思路:

说明:

1 .这里的f(n) 代表的是n个台阶有一次1,2,…n阶的 跳法数。

2 .n = 1时,只有1种跳法,f(1) = 1

  1. n = 2时,会有两个跳得方式,一次1阶或者2阶,这回归到了问题(1) ,f(2) = f(2-1) + f(2-2)

  2. n = 3时,会有三种跳得方式,1阶、2阶、3阶,

​ 那么就是第一次跳出1阶后面剩下:f(3-1);第一次跳出2阶,剩下f(3-2);第一次3阶,那么剩下f(3-3)

​ 因此结论是f(3) = f(3-1)+f(3-2)+f(3-3)

  1. n = n时,会有n中跳的方式,1阶、2阶…n阶,得出结论:

​ f(n) = f(n-1)+f(n-2)+…+f(n-(n-1)) + f(n-n) => f(0) + f(1) + f(2) + f(3) + … + f(n-1)

6 .由以上已经是一种结论,但是为了简单,我们可以继续简化:

​ f(n-1) = f(0) + f(1)+f(2)+f(3) + … + f((n-1)-1) = f(0) + f(1) + f(2) + f(3) + … + f(n-2)

​ f(n) = f(0) + f(1) + f(2) + f(3) + … + f(n-2) + f(n-1) = f(n-1) + f(n-1)

​ 可以得出:

​ f(n) = 2*f(n-1)

  1. 得出最终结论,在n阶台阶,一次有1、2、…n阶的跳的方式时,总得跳法为:

​ 0 | 1 ,(n=0 )

f(n) = 1 | 1 ,(n=1 )

​ n | 2*f(n-1),(n>=2)

public class Solution {
    public int jumpFloorII(int target) {
        if (target == 0) {
            return 1;
        } else if (target == 1) {
            return 1;
        } else {
            return 2 * jumpFloorII(target - 1);
        }
    }
}

public class Solution {
public int jumpFloorII(int target) {
if (target == 0) {
return 1;
} else if (target == 1) {
return 1;
} else {
return 2 * jumpFloorII(target - 1);
}
}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值