剑指offer(04-06)题解

时间:2022-07-23
本文章向大家介绍剑指offer(04-06)题解,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

剑指offer(04-06)题解

  • 04题解--重建二叉树
  • 05题解--用两个栈实现队列
  • 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类型。

思路解析

这里面我们需要懂栈和队列的特性 栈:先进后出 队列:先进先出 通过下面的图来进行讲解 这是栈:

这是队列:

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

源代码

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));
		}
    }
}