一.二叉树的镜像
请完成一个函数,输入一个二叉树,要输出它的镜像
例如:
解决方案:通过分析上面的例子我们可以得到二叉树的镜像其实就是每个节点的左右节点交换位置后的二叉树,所以我们可以遍历二叉树的同时交换左右子节点的位置即可
代码:
TreeNode test(TreeNode root){
if(root==null) return null;//边界条件
TreeNode end=root.left;//中转节点
root.left=test(root.right);
root.right=test(end);
return root;
}
二.对称的二叉树
请实现一个函数,用来判断一颗二叉树是不是对称的,如果一颗二叉树和它的镜像一样,那么它是对称的。
分析问题:我知道二叉树的三种遍历方法:前序遍历(根左右),中序遍历(左根右),后序遍历(左右根)
我们可以针对前序遍历设计一种对称的遍历方法:根右左,如果它遍历的结果和前序遍历一样,则说明二叉树大概率为对称的。
我们要考虑全面,有一些特殊情况符合前面的标准但不对称,例如所有节点元素都相同,但就是不对称。
代码:
public boolean test(TreeNode root){
return root==null?true:help(root.left,root.right);
}
/*
以相反的遍历顺序遍历比较两个子树节点
*/
boolean help(TreeNode L,TreeNode R){
if(L==null&&R==null) return true;
if(L==null||R==null||L.val!=R.val) return false;
return help(L.left,R.right)&&help(L.right,R.left);
}
三.顺时针打印矩阵
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字
解决思路:首先我们可以把矩阵看成若干圈,因此我们可以用一个循环来打印,每次打印一圈
下面我们还要思考循环结束的条件:
我们假设矩阵的行数为rows,列数为columns
我们以左上角为条件,打印第一圈时坐标为(0,0),第二圈时为(1,1)依次类推
下面我们试着找出规律:对于一个5 * 5的矩阵,最后一圈为(2,2)有 5>2 * 2,对于一个 6 * 6 矩阵有:
6>2 * 2,所以我们可以总结出:
当columns>startX * 2且rows>startY * 2时,循环成立(这里的startX,startY)指的是第n圈第一个坐标:
void test(int[][]a,int columns,int rows){
if(a==null||columns<=0||rows<=0) return;
int start=0;
while(columns>startX*2&&rows>startY*2){
help(a,columns,rows,start);//打印一圈
++start;
}
}
下面我们要实现打印一圈的方法help:
我们可以将其分为四步:1从左到右一行,2从上到下一列,3从右到左一行,4从下到上一列
每一步我们根据起始坐标和终止坐标一次for即可,但我们要注意最后一圈可能只有一行或一列,故我们应该仔细分析每一步的前提条件:
第一步总是需要的,如果只有一行就不用往下了
第二步的前提条件是终止行号大于起始行号
第三步的条件是圈内至少有两行两列
第四步的前提是至少有三行两列
所以我们可以:
void help(int[][] a,int columns,int rows,int start){
int endX=columns-1-start;
int endY=rows-1-start;
//打印第一行
for(int i=start;i<=endX;i++) sout(a[start][i]);
//如果起始行号小于终止行号打印第一列
if(start<endY){
for(int i=start+1;i<=endY;i++) sout(a[i][endX]);
}
//如果起始行和列均小于终止行列,打印第二行
if(start<endX&&start<endY){
for(int i=endX-1;i>=start;i--) sout(a[endY][i]);//sout就是System.out.println();
}
//如果有三行两列,打印第二列
if(start<endX&&start<endY-1){
for(int i=endY-1;i>=start+1;i-- ) sout(a[i][start]);
}
}
四.包含min函数的栈
定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的min函数在该栈中,调用min,push,pop的时间复杂度都为1.
解决方案:创建两个普通的栈,其中一个作为辅助栈用来存放最小元素。
Class MinStack{
Stack A,B;//B作为辅助栈
MinStack(){
A=new Stack();
B=new Stack();
}
void push(int x){
A.add(x);
if(B.empty()||B.peek()>=x)
B.add(x);
}
public void pop() {
if(A.pop().equals(B.peek()))
B.pop();
}
public int top() {
return A.peek();
}
public int min() {
return B.peek();
}
}
五.栈的压入弹出序列
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序,假设压入栈的所有数字都不相等。
解决思路:
判断一个序列是不是栈的弹出序列规律:
如果下一个弹出的数字刚好是栈顶数,则直接弹出
如果下一个弹出的数字不在栈顶,则把栈序列中还没有入栈的数字压入辅助栈,知道下一个需要弹出的数字压入栈顶为止。
如果所有数字都压入到栈后仍然没有找到下一个弹出的数字,则该序列不可能是一个弹出序列。
boolean test(int []push,int[] pop){
Stack stack=new Stack();//创建一个新栈
int i=0;//索引游标
for(int num:push){
stack.push(num);//弹入元素
//如果i对应的是stack的栈顶元素,弹出,然后接着执行直到不是
while(!stack.isEmpty()&&stack.peek()==pop[i]){
stack.pop();
i++;
}
}
return stack.isEmpty();//最后,如果stack的元素全部弹出,则表示符合返回true·
}