剑指offer(二)

题目:4. 重建二叉树,5. 用两个栈实现队列,6. 旋转数组的最小数字

4. 重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

思路: 二叉树的前序遍历的第一个值为根结点,在中序遍历中寻找到根节点后,其左侧为左子树,右侧为右子树,如此递归至子树为NULL返回,即可得到整棵二叉树。

例:前序遍历 {1,2,4,7,3,5,6,8},中序遍历{4,7,2,1,5,3,8,6}, 1为根节点,返回节点1,中序遍历数组中1左侧的{4,7,2}为左子树的中序遍历,左子树的前序遍历在前序遍历数组中可以找到为{2,4,7},得到左子树的前序遍历和中序遍历之后,同理得到右子树的前序遍历和中序遍历。返回子树的根节点作为整棵树根节点的左右孩子,继续递归,若子树根节点为NULL,跳出递归。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**

 * Definition for binary tree
 * public class TreeNode {
 * int val;
 * TreeNode left;
 * TreeNode right;
 * TreeNode(int x) { val = x; }
 * }
    */
    public class Solution {
    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
        int index = 0, len = pre.length;
        if(len == 0) return null;
        TreeNode root = new TreeNode(pre[0]);
        for(int i = 0; i < in.length; i++){
            if(in[i] == pre[0]) index = i;
        }
        
        int[] left_pre = new int[index];
        int[] right_pre = new int[len - index - 1];
        int[] left_in = new int[index];
        int[] right_in = new int[len - index - 1];
        
        for(int i = 0; i < index; i++){
            left_pre[i] = pre[i+1];
            left_in[i] = in[i];
            
        }
        for(int j = index + 1; j < len; j++){
            right_pre[j - index - 1] = pre[j];
            right_in[j - index - 1] = in[j];
        }
        root.left = reConstructBinaryTree(left_pre, left_in);
        root.right = reConstructBinaryTree(right_pre, right_in);
        return root;
    }
    }

5. 用两个栈实现队列

用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

思路: 用stack1来存储进入队列的元素,当元素出队列时,如果stack2不为空则直接弹出stack2顶部元素;若为空则,将stack1的元素全部压入stack2,弹出stack2顶部元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.util.Stack;

public class Solution {
    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.isEmpty()){
            while(!stack1.isEmpty()) stack2.push(stack1.pop());
        }
        return stack2.pop();
    }
}

6. 旋转数组的最小数字

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

思路: 利用二分查找减小搜索范围,由题目可知前面的数组中的数值一定大于旋转到尾部的数值,即数组第一个数字是前面非旋转数组的最小值,因此我们用中间的数与数组第一个值相比较,若rotateArray[0] <rotateArray[mid],则旋转部分在mid之后,令left=mid;反之旋转部分在mid之前,令right=mid;当left和right相邻时,此时right一定为数组的最小值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int[] array) {
        if(array.length == 0) return 0;
        int left = 0, right = array.length - 1, middle = -1;
        while (array[left]>=array[right]) {
            if(right-left==1){
                middle = right;
                break;
            }
            middle = (left + right) / 2;
            if (array[middle] >= array[left]) left = middle;
            if (array[middle] <= array[right]) right = middle;
        }
        return array[middle];
    }
}