剑指offer(04-06)题解

简介: 剑指offer(04-06)题解

04题解–重建二叉树


题目描述


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


思路解析


这里我们首先需要知道前序遍历和中序遍历的规则

前序遍历(根左右)

中序遍历(左根右)

我们是通过前序序列的第一个节点来划分中序序列,从而找到该节点的左右子树,之后只需要在对相应的序列做递归操作即可。

这里面我们只要注意一下Arrays.copyOfRange(,,)这个函数是左闭右开的就行了


源代码


import java.util.Arrays;
public class Solution {
      public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
          if(pre.length==0||in.length==0)
            return null;
          TreeNode treeNode=new TreeNode(pre[0]);
          for(int i=0;i<in.length;i++)
          {
            if(in[i]==treeNode.val)
            {
              treeNode.left=reConstructBinaryTree(Arrays.copyOfRange(pre, 1, i+1), Arrays.copyOfRange(in, 0, i));//左子树重建
              treeNode.right=reConstructBinaryTree(Arrays.copyOfRange(pre, i+1, pre.length), Arrays.copyOfRange(in,i+1,in.length));//右子树重建
            }
          }
          return treeNode;
      }
  }


05题解–用两个栈实现队列


题目描述

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

思路解析

这里面我们需要懂栈和队列的特性

栈:先进后出

队列:先进先出

通过下面的图来进行讲解

这是栈:

20200804114635933.png

这是队列:

20200804114300916.png

我们的处理逻辑,主要存储还是通过一个栈来实现,但是需要另外一个栈来充当中间件的功能

20200804115542355.png

源代码

import java.util.Stack;
public class Solution {
    static Stack<Integer> stack1 = new Stack<Integer>();
   static Stack<Integer> stack2 = new Stack<Integer>(); 
   public static void push(int node) {
       stack1.push(node); 
   }
   public static int pop() {
    stack2.clear();//首先保证stack2中是没有任何元素的
    int node;
      if(stack1==null)//避免栈为空时,pop报错
        return (Integer) null;
      else 
      {
        while(!stack1.empty())
        {
          stack2.push(stack1.pop());
        }
        node=stack2.pop();
        while (!stack2.empty()) {
          stack1.push(stack2.pop());
      } 
        return node;
      }
   }
}


06题解–旋转数组的最小数字


题目描述


把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。

输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。

例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。

NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。


思路解析


最简单的方法就是通过暴力来解决,也能通过,但是显然这是不可取的。

主要还是通过二分法来进行,但是这又和我们平常的二分有所不同,他的顺序是部分有序但是二分的整体思想还是能够用的,

二分主要的就是怎么比较,和谁比较。

这里我们采取的是和右端点进行比较。

首先必须明白一点,给我们的数组一定是这样的形式

【{升序数组1},{升序数组2}】 中间有一处是断开的,正是因为他翻转的因素。

现在我们举例说明

第一种情况就是mid<last

举例 {4,5,1,2,3},既然mid<last,那么就可以确定mid-last必定是处于升序的数组之中,这里大家可以通过反证法即可验证。那么显然mid+1~last的元素肯定是大于mid的,所以区间范围就处于0-mid之中,这里因为mid可能刚好是最小的那个元素,所以必须将mid这个位置也包括进去。

第二种情况就是mid>last

举例{3,4,5,1,2},既然mid>last,那么就可以确定0-mid必定是处于升序的数组之中,这里大家也可以通过反证法即可验证。那么显然0-mid的元素都是大于last的,所以区间就确定在了mid+1~last之间了,这里因为mid本身就已经大于last了,所以必定不是最小的元素了,所以排除。

第三种情况就是mid=last

这里面稍微比较复杂,因为=并不能确定我们到底是处于哪一区间的数组之中,所以我们只能慢慢地减少数组中的元素。

举两个例子

{1,2,0,0,0} 这种情况最小值是落在了右边的区间上。

{4,1,2,2,2} 这种情况最小值是落在了左边的区间上。

所以显然我们并不能通过上述的方法进行大幅度的区间减少,只能通过last-1的方式来减少区间范围。


源代码

import java.util.Arrays;
public class Solution {
    public static int minNumberInRotateArray(int [] array) {
    if(array.length==0) return 0;//这是在空数组时进行输出
    if(array.length==1) return array[0];//因为在最后的递归过程中,到最后剩下一个元素时,其实就应该输出了。否则再次进入递归过程那么,就会陷入数组为空的情况,那样就会直接输出0了
    //注意边界的取值情况
    int first=0;
    int last=array.length-1;
    int mid=(last-first)/2;
    //同时注意Arrays.copyOfRange(,,)这个函数是左闭右开的就行了
    if(array[mid]<array[last])
    {
      return minNumberInRotateArray(Arrays.copyOfRange(array,first,mid+1));
    }
    else if(array[mid]>array[last])
    {
      return minNumberInRotateArray(Arrays.copyOfRange(array,mid+1,last+1));
    }
    else 
    {
      return minNumberInRotateArray(Arrays.copyOfRange(array,first,last));
    }
    }
}
相关文章
|
机器人
剑指offer(61-67)题解
剑指offer(61-67)题解
剑指offer(61-67)题解
|
存储 算法
剑指offer(19-24)题解
剑指offer(19-24)题解
剑指offer(19-24)题解