31.二叉树的下一个结点
题目描述
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
解题思路
分两种情况讨论,当当前结点存在右孩子时,其中序遍历的下一个结点就是右孩子左子树最靠左的结点;当其不存在右孩子时,需要找到其所在最大左子树根结点的父结点。
代码
/*
public class TreeLinkNode {
int val;
TreeLinkNode left = null;
TreeLinkNode right = null;
TreeLinkNode next = null; //该结点的父结点
TreeLinkNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public TreeLinkNode GetNext(TreeLinkNode pNode){
if(pNode==null) return null;
TreeLinkNode tmpNode=null;
if(pNode.right!=null){
tmpNode=pNode.right;
while(tmpNode.left!=null) tmpNode=tmpNode.left;
return tmpNode;
}//若该结点存在右孩子,则其中序遍历的下一个结点就是其右孩子左子树最左边的结点
tmpNode=pNode;
while(tmpNode.next!=null){
if(tmpNode.next.left==tmpNode) return tmpNode.next;
tmpNode=tmpNode.next;
}//若该结点不存在右孩子,则应向上追溯直到发现一颗左子树,左子树根结点的父结点即为待求结点中序遍历的下一个结点
return null; //直到追溯到root时也没找到满足要求的结点,说明待求结点已经是中序遍历的最后一个结点,没有下一个结点了
}
}
32.对称的二叉树
题目描述
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
解题思路
递归判断左右子树的各结点是否互为镜像即可,主要考虑几个条件,该镜像结点是否均为空,或者是否一个为空一个非空,两结点均非空时是否结点内两值相等,其子结点是否互为镜像(左子树镜像结点的左孩子对应右子树镜像结点的右孩子,左子树镜像结点的右孩子对应右子树镜像结点的左孩子)。
代码
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
boolean isSymmetrical(TreeNode pRoot){
if(pRoot==null) return true;
return doIsSymmetrical(pRoot.left,pRoot.right); //判断其左子树和右子树是否对称
}
private boolean doIsSymmetrical(TreeNode leftRoot,TreeNode rightRoot){
if(leftRoot==null&&rightRoot==null) return true; //左子树和右子树镜像结点都为空,返回true
if(!(leftRoot!=null&&rightRoot!=null)) return false; //左子树和右子树镜像结点不一致(一个是空,另一个非空),返回false
if(leftRoot.val!=rightRoot.val) return false; //左子树和右子树镜像结点值不同,返回false
if(!doIsSymmetrical(leftRoot.left,rightRoot.right)||
!doIsSymmetrical(leftRoot.right,rightRoot.left))
return false; //递归判断两镜像结点的子结点是否互为镜像结点(如左子树镜像结点的左结点应与右子树镜像结点的右节点互为镜像)
return true; //满足上述条件,返回true
}
}
33.按照之字形顺序打印二叉树
题目描述
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
解题思路
使用两个栈,一个栈stack1存放奇数行结点(从左向右遍历结点),另一个栈stack2存放偶数行结点(从右向左遍历结点)。所以在栈中遍历每层结点时只需要注意如何将其孩子结点压至另一栈中即可。对于存放奇数行的栈stack1中结点而言,因为其下一层需要从右向左遍历,所以将孩子结点压入stack2时需要先压左孩子,后压右孩子;对于存放偶数行的栈stack2则正好相反。
代码
public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
if(pRoot==null) return null;
ArrayList<ArrayList<Integer> > ret=new ArrayList<ArrayList<Integer> >();
Stack<TreeNode> stack1=new Stack<TreeNode>(); //存放奇数行(从左到右)
Stack<TreeNode> stack2=new Stack<TreeNode>(); //存放偶数行(从右到左)
stack1.push(pRoot);
while(!stack1.empty()||!stack2.empty()){
ArrayList<Integer> tmpList=new ArrayList<Integer>();
if(!stack1.empty()){
while(!stack1.empty()){
TreeNode tmpNode=stack1.pop();
tmpList.add(tmpNode.val);
if(tmpNode.left!=null) stack2.push(tmpNode.left);
if(tmpNode.right!=null) stack2.push(tmpNode.right);
} //处理stack1,弹出栈顶元素时将其val值存入当前行的ArrayList对象中
//由于下一个偶数行需要从右向左遍历结点所以将stack1的孩子结点压入stack2时,需要先压入左孩子,后压入右孩子
}else{
while(!stack2.empty()){
TreeNode tmpNode=stack2.pop();
tmpList.add(tmpNode.val);
if(tmpNode.right!=null) stack1.push(tmpNode.right);
if(tmpNode.left!=null) stack1.push(tmpNode.left);
} //类似于上述注释操作,只不过对于stack2要先压入右孩子,后压入左孩子
}
ret.add(tmpList);
}
return ret;
}
34.二叉树的层次遍历
题目描述
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
解题思路
使用先进先出的逻辑结构存放遍历过程中的各结点,遍历到该结点时,先将其左右孩子结点放入队列(实际由一个ArrayList实现),然后将其出队。遍历过程中可以记录下层结点的个数,以控制每层放入ArrayList的个数。
代码
import java.util.ArrayList;
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
ArrayList<ArrayList<Integer> > ret=new ArrayList<ArrayList<Integer> >();
if(pRoot==null) return ret;
int thisLayerNum=1,nextLayerNum=0; //保存此层及下层的结点个数
ArrayList<TreeNode> process=new ArrayList<TreeNode>(); //记录遍历过程中的结点
ArrayList<Integer> tmp=new ArrayList<Integer>(); //保存单层结点的所有值
process.add(pRoot);
while(process.size()!=0){
TreeNode tmpNode=process.get(0);
if(tmpNode.left!=null) {
process.add(tmpNode.left);
nextLayerNum++;
}
if(tmpNode.right!=null) {
process.add(tmpNode.right);
nextLayerNum++;
}
tmp.add(process.remove(0).val);
if((--thisLayerNum)==0){
ret.add(tmp);
tmp=new ArrayList<Integer>();
thisLayerNum=nextLayerNum;
nextLayerNum=0;
}
}
return ret;
}
}
35 把数组排成最小的数
题目描述
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
public class Solution {
public String PrintMinNumber(int [] numbers) {
String[] arr=new String[numbers.length];
for(int i=0;i<numbers.length;++i){
arr[i]=String.valueOf(numbers[i]);
}
sort(arr);
StringBuffer ret=new StringBuffer();
for(int i=0;i<arr.length;++i){
ret.append(arr[i]);
}
return ret.toString();
}
private void sort(String[]arr){
for(int i=0;i<arr.length-1;++i){
int minPos=i;
for(int j=i+1;j<arr.length;++j){
if(compare(arr[minPos],arr[j])){
minPos=j;
}
}
String tmp=arr[i];
arr[i]=arr[minPos];
arr[minPos]=tmp;
}
}
//b是否小于a
private boolean compare(String a,String b){
int minLen=Math.min(a.length(),b.length());
for(int i=0;i<minLen;++i){
char aa=a.charAt(i);
char bb=b.charAt(i);
if(aa>bb) return true;
if(aa<bb) return false;
}
if(a.length()==b.length()) return false;
if(a.length()>b.length()){
String sub=a.substring(minLen);
return compare(sub,b);
}else{
String sub=b.substring(minLen);
return compare(a,sub);
}
}
}