剑指offer题解7-11!!(Java)

剑指offer题解

7 重建二叉树

1570765755613

根据前序和中序遍历,可以确定每颗子树根节点所在的位置,然后根据根节点,划分左右子树,之后再分别在左右子树中重复之前的划分过程。(递归实现)

 private static class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;

        public TreeNode(int val) {
            this.val = val;
        }
    }
//递归求解,第一步划分
    public static TreeNode constructBinaryTreeByPreInOrder(int[] preOrder,int[] inOrder,int preStart,int inStart,int length){
        if (length ==0){
            return null;
        }

        int rootIndex =0;
        for (int i = inStart; i < inStart+ length; i++) {
            if (preOrder[preStart] == inOrder[i]){
                rootIndex = i;
                break;
            }
        }
        int left_length = rootIndex -inStart;
        int right_length =length - left_length -1;

        TreeNode root =new TreeNode(preOrder[preStart]);

        root.left=constructBinaryTreeByPreInOrder(preOrder,inOrder,
                                                  preStart+1, inStart,left_length);
        root.right=constructBinaryTreeByPreInOrder(preOrder,inOrder,                                         			preStart+left_length+1,rootIndex+1,right_length);

        return root;
    }

8 二叉树的下一个节点

1571056951976

分三种情况:

  1. 当前节点有右子树,下一个节点是右子树中最左的节点
  2. 无右子树
  • 父节点的左孩子是当前节点,下一个节点是父节点
  • 遍历该节点的父节点,直到父节点的左孩子是当前节点,下一个节点是父节点
  1. 向上一直找,返现node结点的父节点为null,说明无后继结点了
public class P08FindBinaryTreeNextNode {
    private static class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;
        TreeNode parent;

        public TreeNode(int val) {
            this.val = val;
        }
    }

    public static TreeNode findNextNode(TreeNode node){
        if (node ==null){
            return null;
        }
        //有右孩子,右孩子最左的节点
        if (node.right !=null ){
            return getMostLeft(node.right);
        }else{
            TreeNode parent = node.parent;
            while (parent != null && parent.left != node){
                node = parent;
                parent = node.parent;
            }
            return parent;
        }
    }

    //得到右子树最左的节点
    private static TreeNode getMostLeft(TreeNode node){
        if (node ==null){
            return null;
        }
        while (node.left != null){
            node = node.left;
        }
        return node;
    }
}

9 用两个栈实现队列

1571061821079

创建两个栈push,pop栈,倒数据的操作

  • 如果pop栈为空
  • push 栈往pop栈里倒数据,直到为空
//两个栈实现队列
//方法appendTail,deleteHead
public class P09TwoStackToQueue {
    private static Stack<Integer> pushStack;
    private static Stack<Integer> popStack;

    public P09TwoStackToQueue() {
        pushStack =new Stack<Integer>();
        popStack =new Stack<Integer>();
    }

    public static void appendTail(int val){
        pushStack.push(val);
        pushToPop();
    }

    public static int deleteHead(){
        if (popStack.isEmpty() && pushStack.isEmpty()){
            throw new RuntimeException("队列里没有东西删不掉呢");
        }
        pushToPop();
        return popStack.pop() ;
    }

    //导数据的操作
    private static void pushToPop(){
        if (popStack.isEmpty()){
            while (!pushStack.isEmpty()){
                popStack.push(pushStack.pop());
            }
        }
    }
}
用两个队列实现栈

引入队列queue1和queue2,每次pop操作,就将queue1中的节点都放入queue2中,直至queue1中的节点个数为1,然后再将queue1的节点poll,之后,再交换queue1和queue2中的值。peek操作类似。

public class P09_2TwoQueueToStack {
    private Queue<Integer> queue;
    private Queue<Integer> help;

    public P09_2TwoQueueToStack() {
        queue = new LinkedList<Integer>();
        help = new LinkedList<Integer>();
    }

    public void push(int val) {
        queue.offer(val);
    }

    public int pop() {
        if (queue.isEmpty()) {
            throw new RuntimeException("栈里无元素!!");
        }

        while (queue.size() > 1) {
            help.offer(queue.poll());
        }
        int res = queue.poll();
        swap();
        return res;
    }

    public int peek() {
        if (queue.isEmpty()) {
            throw new RuntimeException("栈里没有元素可以看 !1");
        }
        int res = 0;
        while (!queue.isEmpty()) {
            res = queue.poll();
            help.offer(res);
        }
        swap();
        return res;
    }

    private void swap() {
        Queue<Integer> temp = queue;
        queue = help;
        help = temp;
    }
}

10 斐波那契数列

1571104833926

1.递归,时间复杂度O(2n)

2.循环,时间复杂度O(n)

public class P10Fibonacci {
//递归方法,时间复杂度很高,面试官很不喜欢
    public static int fibonacciRecursive(int n){
        if (n ==0){
            return 0;
        }
        if (n==1){
            return 1;
        }
        return fibonacciRecursive(n-1)+fibonacciRecursive(n-2);
    }
//非递归,效率不是最高,很实用,面试官期待看到的
    public static int fibonacciNoRecursive(int n){
        int[] begin ={0,1};
        if (0<=n&&n<2){
            return begin[n];
        }

        int zero =0;
        int one = 1;
        int res =0;
        for (int i = 2; i <= n; i++) {
            res =zero+one;
            zero =one;
            one =res;
        }
        return res;
    }
}

11 旋转数组的最小数字

1571129856042

解法:

  1. 暴力,时间复杂度O(n)!!简单但复杂度高,不够拿到offer
  2. 二分查找,时间复杂度O(logn)。使用两个指针p1,p2,然后根据计算的mid值来移动p1,p2。
  3. 当arr[p1]== arr[mid] == arr[p2]时,无法判断p1和p2属于哪个递增子数组,直接调用getMin,进行顺序查找。
  4. 当arr[mid]>=arr[p1]时,mid属于p1所在的递增子数组,令p1=mid,继续二分。
  5. 当arr[mid]<=arr[p2]时,处理过程和2类似。
public class P11FindMinNumInRotateArray {
    public static int getMInNumber(int[] arr){
        //判断极端情况
        if (arr[0]<arr[arr.length-1]){
            return arr[0];
        }
        int p1 = 0;
        int p2 = arr.length-1;
        int mid =0;
        int min =arr[0];
        while (arr[p1] >= arr[p2]){
            if (p1 +1 ==p2){
                min =  arr[p2];
                break;
            }
            mid =p1 +((p2-p1)>>1);
            if (arr[p1]==arr[mid]&& arr[mid]==arr[p2]){
                return getMin(arr,p1,p2);
            }
            if (arr[p1]<= arr[mid]){
                p1 = mid;
            }else if(arr[mid] <= arr[p2]){
                p2 = mid;
            }
        }
        return min;
    }
    private static int getMin(int[] arr,int p1,int p2){
        int min =arr[p1];
        for (int i = p1+1; i < p2; i++) {
            if (min> arr[i]){
                min = arr[i];
            }
        }
        return min;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值