PAT 1110 Java

1.题意

判断一棵树是否是完全二叉树,如果是的话,则输出​​YES node​​​,其中这个node代表的是该完全二叉树中最后一个节点;如果不是完全二叉树,则输出​​NO node​​,其中的node是该二叉树的根节点。

2.思路

判断的依据很简单,找到一个节点,如果该节点没有子节点了,但是在该节点之后的节点还有子节点,那说明这棵树就不是一棵完全二叉树。

寻找子节点的过程是广度遍历二叉树的过程。

2.2 其它思路

也有很多其他代码的思路是:

  • 根据节点数n建一棵完整二叉树,将建好的树和这棵树比较,但是我觉得这个算法不好【涉及到建树过程】

3.​​java​​ 代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;

public class P1110 {
public static void main(String[] args) throws IOException {
int [][] tree =new int[30][2];//用于存储每个节点下的子节点编号 => 一个二维数组
//建议这个使用int 型二维数组存储,如果不使用int 型,则在后面进行转换时就比较麻烦

String c = "-";
Reader.init(System.in);
int nodeNum = Reader.nextInt();

//System.out.println("节点数是:"+nodeNum);
for(int i = 0;i< nodeNum;i++) {
for(int j = 0; j< 2;j++) {
c = Reader.next(); //问题的根源 => 可能这个下标不仅仅是一位数
//System.out.println("c = "+c);
if (!c.equals("-")) {
//System.out.println("Integer.valueOf(c) = "+Integer.valueOf(c));
tree[i][j] = Integer.valueOf(c) ; // get the number
}
else{ tree[i][j] = -1 ;}
}
}

// for(int i = 0;i < 9;i++) {
// System.out.print("node "+i+": ");
// for(int j = 0;j < 2;j++) {
// System.out.print(tree[i][j]+" ");
// }
// System.out.println();
// }
int root = 0;
if (nodeNum == 1) {
root = 0;
System.out.println("YES 0");
System.exit(0);//直接退出
} else {
//找出根节点
//array[] = -2 表示的是根节点
int array[] = new int[nodeNum];
//初始化一遍
for(int i = 0;i< nodeNum;i++) {
array[i] = -2;
}
for(int i = 0;i< nodeNum;i++ ) {
for(int j = 0;j < 2;j++) {
if (tree[i][j] == -1) {
array[i] = i;
} else {
array[tree[i][j]] = tree[i][j];
}
}
}
for(int i = 0;i<nodeNum;i++) {
if (array[i] == -2) {
root = i;//get the value of root
//System.out.println("root :"+ i);
}
}
}

//=================================================================
//接下来就是针对root 开始遍历整个二叉树,判断是否是完整二叉树
Queue<Integer> queue = new LinkedList<>();
queue.add(root);
int leftNode ;
int rightNode;

int tempRoot = 0;
int lastNode = 0;
while (!queue.isEmpty()) {
tempRoot = queue.peek(); //队首元素
//System.out.println("tempRoot = "+tempRoot);
leftNode = tree[tempRoot][0]; // 得到根节点的左节点
rightNode = tree[tempRoot][1]; // 得到根节点的左节点
if (leftNode == -1 && rightNode != -1) { //有右节点,但是没有左节点 => 肯定不是完全二叉树
System.out.println("NO "+root);
System.exit(0);
}

//如果有左右子节点均为空,或者左子树不为空,但是右子树为空
// 则需要遍历queue 中之后的所有的节点,判断是不是完全二叉树
if ((leftNode == -1 && rightNode == -1) || (leftNode != -1 && rightNode == -1)) {
if(leftNode!=-1){
queue.add(leftNode);
}
if(rightNode!=-1){
queue.add(rightNode);
}

queue.poll(); //先将队首移出,然后接着比较队首之后的元素
while (!queue.isEmpty()) {//遍历检查是否还有节点存在子节点
tempRoot = queue.peek(); //队首元素
leftNode = tree[tempRoot][0]; // 得到根节点的左节点
rightNode = tree[tempRoot][1]; // 得到根节点的左节点
if (leftNode != -1 || rightNode != -1) {//说明还有子节点
System.out.println("NO "+root);
System.exit(0);
}
// System.out.println("队首元素是: "+queue.peek());
lastNode = tempRoot;
queue.poll(); //
}
}
if(leftNode!=-1){
queue.add(leftNode);
}
if(rightNode!=-1){
queue.add(rightNode);
}
//System.out.println("队首元素是: "+queue.peek());
queue.poll();
lastNode = tempRoot;
}
System.out.println("YES "+lastNode);
}
}


class Reader {
static BufferedReader reader;
static StringTokenizer tokenizer;

/** call this method to initialize reader for InputStream */
static void init(InputStream input) throws IOException {
reader = new BufferedReader(new InputStreamReader(input) );
tokenizer = new StringTokenizer("");
//这里初始化tokenizer只是为了进入下面的while()循环,而不是别的原因。
//那么还有优化的空间么?
}

/** get next word */
static String next() throws IOException {
while ( ! tokenizer.hasMoreTokens() ) {//如果后面还有数据,则直接返回
//TODO add check for eof if necessary
tokenizer = new StringTokenizer(reader.readLine() );//否则,读取下一行
}
return tokenizer.nextToken();
}

static int nextInt() throws IOException {
return Integer.parseInt( next() );
}

static double nextDouble() throws IOException {
return Double.parseDouble( next() );
}

//获取字符 => 因为 next()方法返回的是一个String
static char nextChar() throws IOException {
return next().charAt(0);
}
}

4. 测试用例

/* 注意这里在John 159之后有一个换行。
9
7 8
- -
- -
- -
0 1
2 3
4 5
- -
- -



8
- -
4 5
0 6
- -
2 3
- 7
- -
- -

8
- -
4 5
0 6
- -
2 3
7 -
- -
- -




1
- -


3
- 1
- 2
- -

2
- 1
- -

4
3 1
2 -
- -
- -



4
1 2
- -
3 -
- -


5
1 2
4 -
3 -
- -
- -



6
1 2
4 5
3 -
- -
- -
- -
*/

5.执行结果

PAT 1110 Java_java

还是有一个样例过不掉。。。

坑点


  • 二叉树的下标可能会超过一位数,所以不能使用​​char​​​字符作为下标,而是应该使用​​String​​,然后再转换成int
  • 注意特殊用例【比如只有一个节点的时候】