面试题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;
}
}