剑指offer-第四题

import java.util.HashMap;

//Definition for binary tree
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    TreeNode(int x) {
        val = x;
    }
}

/**
 * 目标:
 * 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。
 * 假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
 * 例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},
 * 则重建二叉树并返回。
 * <p>
 * 思路:
 * 因为前序遍历先输出当前节点,再输出左子树,最后输出右子树
 * 中序遍历先输出左子树,再输出当前节点,最后输出右子数
 * <p>
 * 因此
 * 1、在中序遍历中找到前序遍历的当前节点,确定当前数组中当前节点在中序遍历的位置(当前位置的左边都是左子树,当前位置的右边都是右子树)
 * 2、确定左子数组(左子树),在前序中序遍历的位置
 * 3、确定右子数组(右子树),在前序中序遍历的位置
 */
public class Solution4 {
    public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
        if (pre == null || in == null) {
            return null;
        }
        HashMap<Integer, Integer> hashMap = new HashMap<>();
        for (int i = 0; i < in.length; i++) {
       //记录中序遍历各元素的index hashMap.put(in[i], i); } TreeNode root
= buildTree(pre, 0, pre.length - 1, in, 0, in.length - 1, hashMap); return root; } private TreeNode buildTree(int[] pre, int preStart, int preEnd, int[] in, int inStart, int inEnd, HashMap hashMap) { //一、判断非法条件 if (preStart > preEnd || inStart > inEnd) { return null; } //二、处理条件 TreeNode head = new TreeNode(pre[preStart]); //1、在中序遍历中找到前序遍历的当前节点 int index = (int) hashMap.get(pre[preStart]); //三、缩小问题规模 //2、确定左子数组(左子树),在前序、中序遍历的位置 head.left = buildTree(pre,preStart+1,preStart+1+(index-inStart),in,inStart,index-1,hashMap); //3、确定右子数组(右子树),在前序、中序遍历的位置 head.right= buildTree(pre,preStart+1+(index-inStart),preEnd,in,index+1,inEnd,hashMap); //四、结果 return head; } }

小结

算法思想

递归算法是一种调用自身函数的算法(二叉树的许多性质在定义上就满足递归)

举例:

汉诺塔问题:有三个塔ABC,一开始的时候,在塔A上放着n个盘子,它们自底向上按照从大到小的顺序叠放.现在要求将塔A中所有的盘子搬到塔C,让你打印出搬运的步骤.在搬运的过程中,每次只能搬运一个盘子,另外,任何时候,无论在哪个塔上,大盘子不能放在小盘子的上面.

 解法

1、从最终的结果出发,要把n个盘子按照大小顺序叠放在塔C,就需要将塔A的底部最大的盘子搬到塔C;

2、为了实现步骤1,需要将除了这个最大盘子之外的其余盘子都放到塔B

由上可知,将原来的问题规模从n个盘子变成(n-1)个盘子,即将(n-1)个盘子转移到塔B

如果一个函数,能将n个盘子从塔A,借助塔B,搬到塔C.那么,也可以利用该函数将(n-1)个盘子从塔A,借助塔C,搬到塔B.同理,不断地把问题规模变小,n1,也就是只有1个盘子时,直接打印出步骤

代码

Void hano(char a,char b, char c,int n){

If(n > 0){

Hano(a,c,b,n-1);

Move(a,c);

Hano(b,a,c,n-1);

}

}

递归可以解释成把问题缩小为最简化的方式, 然后再在此基础上进行解题.为何如此说,见一下步骤:

通俗来说,把要实现的递归函数看成是已经实现好的,直接利用解决一些子问题,然后需要考虑的就是如何根据子问题的解以及当前面对的情况得出答案.这种算法也被称为自顶向下(Top-Down)的算法.

通过上述例题,来归纳总结以下递归函数的解题模版

解题步骤

1、判断当前情况是否非法,如果非法就立即返回,这一步也被称为完整性检查

例如,看看当前处理情况是否越界,是否出现了不满足条件的情况.通常,这一部分代码都是写在前面的.

2、判断是否满足结束递归的条件.在这一步当中,处理的基本上都是一些推导过程当中所定义的初始情况

3、将问题的规模缩小,递归调用.并归并排序和快速排序中,我们将问题的规模缩小了一半,而在汉诺塔和解码例子中,我们将问题的规模缩小了一个

4、利用在小问题中的答案,结合当前的数据进行整合,得出最终的答案.

Function fn(n){
//第一步:判断输入或状态是否非法?
If(input/state is invalid){
Return;
}

//第二步:判断递归是否应当结束?
If(match condition){
Return some value;
}

//第三步:缩小问题规模
Result1 = fn(n1)
Result2 = fn(n2)
...
//第四步:整合结果
Return combine(result1,result2) 
}
原文地址:https://www.cnblogs.com/Adam-Ye/p/13445502.html