剑指Offer面试题(第十九天)面试题31、32

面试题31:栈的压入、弹出序列


     * 题目:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。
     * 假设压入栈的数字均不相等。例如,序列{1,2,3,4,5}是某栈的压栈序列,
     * 序列{4,5,3,2,1}是该压栈序列对应的一个弹出序列,
     * 但{4,3,5,1,2}就不可能是该压栈序列的弹出序列。
     * 
     * 思路:*******************判断序列是否为栈的弹出序列,因为题设并没有提到使用栈进行操作,所以这就意味着不一定要使用栈去进行判断(避免误区)
     * 只要能解决问题,使用什么数据结构都是可行的
     * 一层循环模拟push元素压入,注意for中结束条件要保证i<=length,因为有可能要走到最后,才开始出栈的情况
     *         这种情况下,i值会大于1,还要注意push次数应该<length,保证个数正确
     * 第二层循环模拟pop元素弹出,判断list是否为空,若不为空,则比较两个值(出栈序列的第一个值+list的表头值)是否相等,相等则弹出+弹出序列数组向下走,判断两个值是否相等
     *                                     否则,则进行压入元素操作。

package Test;

import java.util.LinkedList;

public class No31isPopOrder {

	/*面试题31:栈的压入、弹出序列
	 * 题目:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。
	 * 假设压入栈的数字均不相等。例如,序列{1,2,3,4,5}是某栈的压栈序列,
	 * 序列{4,5,3,2,1}是该压栈序列对应的一个弹出序列,
	 * 但{4,3,5,1,2}就不可能是该压栈序列的弹出序列。
	 * 
	 * 思路:*******************判断序列是否为栈的弹出序列,因为题设并没有提到使用栈进行操作,所以这就意味着不一定要使用栈去进行判断(避免误区)
	 * 只要能解决问题,使用什么数据结构都是可行的
	 * 一层循环模拟push元素压入,注意for中结束条件要保证i<=length,因为有可能要走到最后,才开始出栈的情况
	 *         这种情况下,i值会大于1,还要注意push次数应该<length,保证个数正确
	 * 第二层循环模拟pop元素弹出,判断list是否为空,若不为空,则比较两个值(出栈序列的第一个值+list的表头值)是否相等,相等则弹出+弹出序列数组向下走,判断两个值是否相等
	 * 									否则,则进行压入元素操作。
	 * 
	 * */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

		No31isPopOrder p = new No31isPopOrder();
		//压入序列
		int[] sPush = {1,2,3,4,5};
		//弹出序列
		int[] sPop = {5,3,4,2,1};
		
		if(p.isPopOrder(sPush,sPop))
			System.out.println("是压入序列的一个弹出序列!");
		else
			System.out.println("不是压入序列的一个弹出序列!!!");
		
	}

	//判断弹出序列是否正确      
	public Boolean isPopOrder(int[] sPush, int[] sPop) {
		// TODO Auto-generated method stub
		if(sPush == null || sPop == null || sPush.length != sPop.length) {
			return false;
		}
		
		//链表   模拟入栈+出栈
		LinkedList<Integer> list = new LinkedList<Integer>();
		//弹出指针
		int popIndex = 0;
		//执行压入和弹出操作的过程  判断是不是其中的一个序列
		for(int i = 0;i <= sPush.length;i++) {   //此处为push元素处   模拟push
			
			//从第一个压入开始到最后一个压入结束
			while(!list.isEmpty()) {       //此处为pop元素处    模拟pop
				//若list不为空,判断两个值是否相等
				
				if(list.getFirst() == sPop[popIndex]) {
					
					//若相等,表示这个元素存在且弹出正确,则将其在list中删除,并移动到下一个出栈元素处
					list.removeFirst();
					popIndex++;
					continue;
				}
				else {
					//若不相等,若有元素接着压入list,若没有则退出
					break;
				}
				
			}
			if(i < sPush.length) {
				list.addFirst(sPush[i]);
				//System.out.println("i值"+i);
			}
			
		}
		
		if(list.isEmpty() && sPop.length == popIndex) {//全部正确弹出
			return true;
		}
		
		return false;
		
		
		
	}

}

 * 面试题32:从上到下打印二叉树    树的遍历 (按层次)


     * 题目一:不分行从上到下打印二叉树


     * 从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。
     * 例如:输入8->8   8->10 这样的二叉树,打印出8,6,10,5,7,9,11
     *         6->5   6->7
     *         10->9  10->11
     * 
     * 思路:从上到下打印二叉树时,借助一个队列进行操作
     * 从头节点开始进行打印,每次打印时,若是该节点有子节点,则都将该子节点放入队列的末尾;
     * 接下来取队列的头部元素,重复之前的打印操作,直到所有的节点都被打印出来

package Test;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;

public class No32First_PrintBinaryTreeFromTopToBottom {

	/*
	 * 面试题32:从上到下打印二叉树    树的遍历 (按层次)
	 * 题目一:不分行从上到下打印二叉树
	 * 从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。
	 * 例如:输入8->8   8->10 这样的二叉树,打印出8,6,10,5,7,9,11
	 * 		6->5   6->7
	 * 		10->9  10->11
	 * 
	 * 思路:从上到下打印二叉树时,借助一个队列进行操作
	 * 从头节点开始进行打印,每次打印时,若是该节点有子节点,则都将该子节点放入队列的末尾;
	 * 接下来取队列的头部元素,重复之前的打印操作,直到所有的节点都被打印出来
	 * 
	 * 
	 * */
	
	static class BinaryTreeNode{
		int val;
		BinaryTreeNode left;
		BinaryTreeNode right;
		
		BinaryTreeNode(int val){
			this.val = val;
		}
		
	}
	public static void main(String[] args) {

		// TODO Auto-generated method stub
		No32First_PrintBinaryTreeFromTopToBottom p = new No32First_PrintBinaryTreeFromTopToBottom();
		BinaryTreeNode root1 = new BinaryTreeNode(8);
		BinaryTreeNode one = new BinaryTreeNode(6);
		BinaryTreeNode two = new BinaryTreeNode(10);
		BinaryTreeNode three = new BinaryTreeNode(5);
		BinaryTreeNode four = new BinaryTreeNode(7);
		BinaryTreeNode five = new BinaryTreeNode(9);
		BinaryTreeNode six = new BinaryTreeNode(11);
		
		root1.left = one;
		root1.right = two;
		one.left = three;
		one.right = four;
		two.left = five;
		two.right = six;
		three.left = null;
		three.right = null;
		four.left = null;
		four.right = null;
		five.left = null;
		five.right = null;
		six.left = null;
		six.right = null;
		
		
		System.out.println("不分行从上到小(行中从左到右)打印二叉树:");
		ArrayList<Integer> list = new ArrayList<>();
		list = p.PrintBinaryTreeFromTopToBottom(root1);
		for(int i = 0;i < list.size();i++) {
			System.out.print(list.get(i)+"  ");
		}
		System.out.println();
		
		
	}
	
	
	//不分行从上到下打印二叉树
	public ArrayList<Integer> PrintBinaryTreeFromTopToBottom(BinaryTreeNode root1) {
		// TODO Auto-generated method stub
		if(root1 == null) {
			return new ArrayList<>();
		}
		ArrayList<Integer> list = new ArrayList<>();//记录要打印的顺序
		Queue<BinaryTreeNode> queue = new LinkedList<> ();//队列  存入子节点
		//根节点root入队列
		queue.add(root1);
		
		//只要队列不为空,就对其进行判断 看是否要打印、入队列
		while(!queue.isEmpty()) {
			//记录一下打印的这个节点  因为要用到其左右节点,所以需要记录,不然出队列后就找不到了
			BinaryTreeNode temp = queue.poll();
			//将要打印的存入list中
			
			list.add(temp.val);
			
			if(temp.left != null) {
				queue.add(temp.left);
			}
			if(temp.right != null) {
				queue.add(temp.right);
			}

		}
		return list;
		
	}
	

}


     * 题目二:分行从上到下导引二叉树


     * 从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印一行。
     * 例如:输入8->8   8->10 这样的二叉树,打印出8
     *         6->5   6->7                  6  10
     *         10->9  10->11              5  7  9  11
     * 
     * 
     * 思路:在题目一的基础上(借助队列,首先将节点入队列, 
     *                     循环中:记录当前这个队列的节点并从(头部)出队列,输出这个节点值,
     *                     并用之前记录的刚刚出队列的这个节点去进行判断,判断其左右子节点是否存在,存在则从(尾部)入队列
     *                     直到队列中已经没有数据了,)
     * 因为要进行分行打印,所以要加入两个标志位  toBePrinted 记录本行还剩下多少个元素没有打印
     *                                     nextLine 记录下一行有多少要打印的元素

package Test;

import java.util.LinkedList;
import java.util.Queue;

import Test.No32First_PrintBinaryTreeFromTopToBottom.BinaryTreeNode;

public class No32Second_PrintBinaryTreeFromTopToBottomByRow {

	/*
	 *  面试题32从上到下打印二叉树     
	 * 题目二:分行从上到下导引二叉树
	 * 从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印一行。
	 * 例如:输入8->8   8->10 这样的二叉树,打印出8
	 * 		6->5   6->7				  6  10
	 * 		10->9  10->11			  5  7  9  11
	 * 
	 * 
	 * 思路:在题目一的基础上(借助队列,首先将节点入队列, 
	 * 					循环中:记录当前这个队列的节点并从(头部)出队列,输出这个节点值,
	 * 					并用之前记录的刚刚出队列的这个节点去进行判断,判断其左右子节点是否存在,存在则从(尾部)入队列
	 * 					直到队列中已经没有数据了,)
	 * 因为要进行分行打印,所以要加入两个标志位  toBePrinted 记录本行还剩下多少个元素没有打印
	 * 									nextLine 记录下一行有多少要打印的元素
	 *  
	 * 
	 * */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

		No32Second_PrintBinaryTreeFromTopToBottomByRow p = new No32Second_PrintBinaryTreeFromTopToBottomByRow();
		BinaryTreeNode root1 = new BinaryTreeNode(8);
		BinaryTreeNode one = new BinaryTreeNode(6);
		BinaryTreeNode two = new BinaryTreeNode(10);
		BinaryTreeNode three = new BinaryTreeNode(5);
		BinaryTreeNode four = new BinaryTreeNode(7);
		BinaryTreeNode five = new BinaryTreeNode(9);
		BinaryTreeNode six = new BinaryTreeNode(11);
		
		root1.left = one;
		root1.right = two;
		one.left = three;
		one.right = four;
		two.left = five;
		two.right = six;
		three.left = null;
		three.right = null;
		four.left = null;
		four.right = null;
		five.left = null;
		five.right = null;
		six.left = null;
		six.right = null;
		
		System.out.println("分行从上到下打印二叉树:");
		p.PrintBinaryTreeFromTopToBottomByRow(root1);
	}
	
	//分行从上到下打印二叉树
		public void PrintBinaryTreeFromTopToBottomByRow(BinaryTreeNode root1) {
			// TODO Auto-generated method stub
			if(root1 == null) {
				return ;
			}
			//需要记录两个数值:
			//一个是记录本行还剩下多少个元素要打印
			int toBePrinted = 1;
			//另一个是记录下一行要打印的个数
			int nextLine = 0;
			
			Queue<BinaryTreeNode> queue = new LinkedList<> ();//队列  存入子节点
			//根节点root入队列
			queue.add(root1);
			
			//只要队列不为空,就对其进行判断 看是否要打印、入队列
			while(!queue.isEmpty()) {
				//记录一下打印的这个节点
				BinaryTreeNode temp = queue.poll();
				//将要打印的存入list中
				
				System.out.print(temp.val+"  ");
				
				if(temp.left != null) {
					queue.add(temp.left);
					nextLine++;
				}
				if(temp.right != null) {
					queue.add(temp.right);
					nextLine++;
				}
				toBePrinted--;
				if(toBePrinted == 0) {
					System.out.println();
					toBePrinted = nextLine;
					nextLine = 0;
				}

			}
			
		}


		

}

 * 题目三:之字形打印二叉树


     * 请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,
     * 第二行按照从右到左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
     * 例如:按之字形打印8->8   8->10 这样的二叉树,打印出8
     *               6->5   6->7                10 6
     *               10->9  10->11                5  7  9  11
     * 
     * 思路1:按照这个规则,进行模拟一下,找其隐含的规律:
     *                   循环:1>    将8输出,然后将8的子节点(左节点、右节点)6、10存入,(输出顺序10,6);进出顺序符合栈的特性(先进后出)栈内:6 10
     *             2>    将10输出,然后将10的子节点(左节点、右节点)9、11存入 , (输出顺序9、11);进出顺序不符合栈的特性(先进先出)栈内:6 9 11
     *          3>     出错了,可以看出6,10,我们使用栈是对的,但是到了下一层就出了问题,若是改变入栈的顺序(右节点、左节点)11、9,(输出顺序9、11)那就正确了;栈内:6 11 9
     *          4>     但是现在仍旧不对,因为我们想要输出6,可是它被压在了栈底,这时,发现一个栈解决不了了,那我们再加一个栈,将二者分开根节点与子节点分开存放在两个栈中:看一下可不可行
     *          5>     从头开始:首先8输出,然后将8的子节点(左节点、右节点)6、10存入栈1,输出顺序10、6;栈1中  6 10      奇数层
     *                         然后10输出,将 10的子节点(右节点、左节点)11、9存入栈2,输出顺序9、11;栈2中  11 9        偶数层
     *                         然后6输出,将6的子节点(右节点、左节点)7、5存入栈2,输出顺序5、7;栈2中 11 9 7 5           偶数层
     *                         这样输出正好是要的之字形顺序
     *  总结规律:输出节点,奇数层将子节点按照左、右的顺序进行存储;偶数层将子节点按照右、左的顺序进行存储。
     *              输入输出就是遵循栈的特性先进后出
     *  
     *将其看成是一个二维数组,将每一行存储到数组的每一行中,故设置一个二维的整型数组list;
     *将stack1存储奇数层节点,stack2存储偶数层节点
     *设置一个level记录到达了第几层,从第一层开始:
     *只要两个栈有一个为非空战栈,则循环执行:1>先判断是奇数层还是偶数层,
     *                            2>若是奇数层,设置一个临时变量记录temp:每一层设置为一个一维整形数组存储每一行的数据
     *                                    栈1是存储奇数层的,所以处理栈1的数据,只要栈1不为空,
     *                                    就将栈顶节点弹出并记录进node(记录是为了后边要使用它的左节点和右节点,防止找不到),
     *                                    把弹出的节点node再放入到temp中,然后判断是否有左+右子树,如有压入是stack2中
     *                                    然后,再将temp中元素放入到list中,并且层数level+1,开始执行下一层的循环
     *                            3>若是偶数层,。。。与奇数层相似,这里不再赘述

package Test;

import java.util.ArrayList;
import java.util.Stack;

import Test.No32First_PrintBinaryTreeFromTopToBottom.BinaryTreeNode;

public class No32Third_PrintBinaryTreeByZ {

	/*面试题32:从上到下打印二叉树
	 * 题目三:之字形打印二叉树
	 * 请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,
	 * 第二行按照从右到左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
	 * 例如:按之字形打印8->8   8->10 这样的二叉树,打印出8
	 * 			  6->5   6->7			    10 6
	 * 			  10->9  10->11			    5  7  9  11
	 * 
	 * 思路1:按照这个规则,进行模拟一下,找其隐含的规律:
	 *                   循环:1>    将8输出,然后将8的子节点(左节点、右节点)6、10存入,(输出顺序10,6);进出顺序符合栈的特性(先进后出)栈内:6 10
	 * 		    2>    将10输出,然后将10的子节点(左节点、右节点)9、11存入 , (输出顺序9、11);进出顺序不符合栈的特性(先进先出)栈内:6 9 11
	 *          3>     出错了,可以看出6,10,我们使用栈是对的,但是到了下一层就出了问题,若是改变入栈的顺序(右节点、左节点)11、9,(输出顺序9、11)那就正确了;栈内:6 11 9
	 *          4>     但是现在仍旧不对,因为我们想要输出6,可是它被压在了栈底,这时,发现一个栈解决不了了,那我们再加一个栈,将二者分开根节点与子节点分开存放在两个栈中:看一下可不可行
	 *          5>     从头开始:首先8输出,然后将8的子节点(左节点、右节点)6、10存入栈1,输出顺序10、6;栈1中  6 10      奇数层
	 *          		       然后10输出,将 10的子节点(右节点、左节点)11、9存入栈2,输出顺序9、11;栈2中  11 9        偶数层
	 *          		       然后6输出,将6的子节点(右节点、左节点)7、5存入栈2,输出顺序5、7;栈2中 11 9 7 5           偶数层
	 *          		       这样输出正好是要的之字形顺序
	 *  总结规律:输出节点,奇数层将子节点按照左、右的顺序进行存储;偶数层将子节点按照右、左的顺序进行存储。
	 *  			输入输出就是遵循栈的特性先进后出
	 *  
	 *将其看成是一个二维数组,将每一行存储到数组的每一行中,故设置一个二维的整型数组list;
	 *将stack1存储奇数层节点,stack2存储偶数层节点
	 *设置一个level记录到达了第几层,从第一层开始:
	 *只要两个栈有一个为非空战栈,则循环执行:1>先判断是奇数层还是偶数层,
	 *							2>若是奇数层,设置一个临时变量记录temp:每一层设置为一个一维整形数组存储每一行的数据
	 *									栈1是存储奇数层的,所以处理栈1的数据,只要栈1不为空,
	 *									就将栈顶节点弹出并记录进node(记录是为了后边要使用它的左节点和右节点,防止找不到),
	 *									把弹出的节点node再放入到temp中,然后判断是否有左+右子树,如有压入是stack2中
	 *									然后,再将temp中元素放入到list中,并且层数level+1,开始执行下一层的循环
	 *						    3>若是偶数层,。。。与奇数层相似,这里不再赘述
	 *  	        
	 *                               
	 * */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

		No32Third_PrintBinaryTreeByZ p = new No32Third_PrintBinaryTreeByZ();
		
		BinaryTreeNode root1 = new BinaryTreeNode(8);
		BinaryTreeNode one = new BinaryTreeNode(6);
		BinaryTreeNode two = new BinaryTreeNode(10);
		BinaryTreeNode three = new BinaryTreeNode(5);
		BinaryTreeNode four = new BinaryTreeNode(7);
		BinaryTreeNode five = new BinaryTreeNode(9);
		BinaryTreeNode six = new BinaryTreeNode(11);
		
		root1.left = one;
		root1.right = two;
		one.left = three;
		one.right = four;
		two.left = five;
		two.right = six;
		three.left = null;
		three.right = null;
		four.left = null;
		four.right = null;
		five.left = null;
		five.right = null;
		six.left = null;
		six.right = null;
		
		System.out.println("之字形打印二叉树");
		ArrayList<ArrayList<Integer>> list = new ArrayList<ArrayList<Integer>>();
		list = p.PrintBinaryTreeByZWord(root1);
		System.out.println(list);
	}

	
	    //Z字形打印二叉树
		public ArrayList<ArrayList<Integer>> PrintBinaryTreeByZWord(BinaryTreeNode root1) {
			// TODO Auto-generated method stub
			if(root1 == null) {
				return new ArrayList<ArrayList<Integer>>();
			}
			//存奇数层节点
			Stack<BinaryTreeNode> stack1 = new Stack<BinaryTreeNode>();
			//存偶数层节点
			Stack<BinaryTreeNode> stack2 = new Stack<BinaryTreeNode>();
			//第level层
			int level = 1;
			stack1.push(root1);
			//将数据存入二维数组中   然后将其返回即可  
			//每一行存入对应的数组行中
			ArrayList<ArrayList<Integer>> list = new ArrayList<ArrayList<Integer>>();			
			while(!stack1.isEmpty() || !stack2.isEmpty()) {
				//先将当前行子节点放入另一栈中,然后输出节点值
				//奇数层  存储顺序:左节点+右节点
				if(level % 2 != 0) {
					//临时存放一行的数据
					ArrayList<Integer> temp = new ArrayList<Integer>();
					while(!stack1.empty()) {//结束条件是:当栈为空时结束,全部遍历完
						//记录删除的节点,为了找其下方节点(左节点+右节点)
						BinaryTreeNode node = stack1.pop();
						temp.add(node.val);
						if(node.left != null) 
							stack2.push(node.left);
						if(node.right != null)
							stack2.push(node.right);
					}
					//将临时存放一行的数据存放到 二维数组的一行中
					//并将层数加1  遍历下一层
					//if(!temp.isEmpty()) {
					//此处判断省略,因为temp为空的话表示没有执行上边的while循环,表明stack1是空的,表明不是奇数层,那就不会执行这个if(level%2 != 0)
					//因此此判断删除
					list.add(temp);
					level++;
					//}		
				}//if(level % 2 != 0)结束
				else {//if(level % 2 == 0开始)
					ArrayList<Integer> temp = new ArrayList<Integer>();
					while(!stack2.empty()) {//结束条件是:当栈为空时结束,全部遍历完
						BinaryTreeNode node = stack2.pop();
						temp.add(node.val);
						if(node.right != null)
							stack1.push(node.right);
						if(node.left != null)
							stack1.push(node.left);
					}
					//if(!temp.isEmpty()) {  //原因同上
					list.add(temp);
					level++;
					//}
					
				}//if(level % 2 == 0)结束
				
			}//while
			return list;
		}
}

猜你喜欢

转载自blog.csdn.net/weixin_43137176/article/details/89302775