剑指offer高频题系列题解分析
4.重建二叉树
给定某二叉树的前序遍历和中序遍历,请重建出该二叉树并返回它的头结点。
例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如下图所示。
提示:
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,4,7,3,5,6,8} = pre
中序序列{4,7,2,1,5,3,8,6} = in
- 根据当前前序序列的第一个结点确定根结点,为 1
- 找到 1 在中序遍历序列中的位置,为 in[3]
- 切割左右子树,则 in[3] 前面的为左子树, in[3] 后面的为右子树
- 则切割后的左子树前序序列为:{2,4,7},切割后的左子树中序序列为:{4,7,2};切割后的右子树前序序列为:{3,5,6,8},切割后的右子树中序序列为:{5,3,8,6}
- 对子树分别使用同样的方法分解
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
-
n = 2时,会有两个跳得方式,一次1阶或者2阶,这回归到了问题(1) ,f(2) = f(2-1) + f(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)
- 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)
- 得出最终结论,在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);
}
}
}