【剑指Offer面试题】 九度OJ1521:二叉树的镜像
2015-07-31 11:29
447 查看
题目链接地址:
http://ac.jobdu.com/problem.php?pid=1521
题目描述:
输入一个二叉树,输出其镜像。
输入:
输入可能包含多个测试样例,输入以EOF结束。
对于每个测试案例,输入的第一行为一个整数n(0<=n<=1000,n代表将要输入的二叉树节点的个数(节点从1开始编号)。接下来一行有n个数字,代表第i个二叉树节点的元素的值。接下来有n行,每行有一个字母Ci。
Ci=’d’表示第i个节点有两子孩子,紧接着是左孩子编号和右孩子编号。
Ci=’l’表示第i个节点有一个左孩子,紧接着是左孩子的编号。
Ci=’r’表示第i个节点有一个右孩子,紧接着是右孩子的编号。
Ci=’z’表示第i个节点没有子孩子。
输出:
对应每个测试案例,
按照前序输出其孩子节点的元素值。
若为空输出NULL。
样例输入:
7
8 6 10 5 7 9 11
d 2 3
d 4 5
d 6 7
z
z
z
z
样例输出:
8 10 11 9 6 7 5
先前序遍历二叉树的每个节点,如果结点有子节点,则把左右孩子结点进行对换,然后向下递归,直到第一个叶子节点结束。
二叉树每个点都会访问到一次,所以时间复杂度为O(n)。
空间复杂度O(1)。
这题算法理解了,代码好写,难而且折磨人的地方却是在测试用例和输入输出格式上。对于面试准备来说,过多拘泥于这些AC上,貌似浪费时间啊。
注意:
由于输入有数字和字符,所以要考虑输入缓冲队列的问题。如果某行含有字符则在最后会留下换行符,然后读取下一行的输入字符时,就会读取错误字符。因此在下一行数据开始输入前,要刷新缓冲区, 通过while((ch = getchar()) != ‘\n’) ; while–getchar()来吃掉前面scanf输入的’\n’。
输出格式上,输出的各节点要有一个空格,且输出最后一个元素后没有空格,而是输出一个换行符。
测试用例中,根节点是哪一个,题目并没指定,所以要根据入度来判断哪个才是根,根节点入度为0。(这里坑死我了,一直WA。潜意识里认为第一个元素就是根节点。。。。。。。)
如何根据入度来判断根节点以及构造二叉树呢:
将各个结点都看成是只有根结点而没有左右孩子的二叉树
根据各个结点之间的链接关系构造每个结点的左右孩子结点,将每个结点并入到所要构造的二叉树中;
确定根结点, 如果某个结点不是任何结点的孩子结点,则该结点就是根结点。
更详细的处理方法看代码注释!!
输入有数字和字符,考虑输入缓冲队列的问题。
根据入度来判断根节点的方法
http://ac.jobdu.com/problem.php?pid=1521
题目1521:二叉树的镜像
时间限制:1 秒内存限制:128 兆特殊判题:否提交:2075解决:564题目描述:
输入一个二叉树,输出其镜像。
输入:
输入可能包含多个测试样例,输入以EOF结束。
对于每个测试案例,输入的第一行为一个整数n(0<=n<=1000,n代表将要输入的二叉树节点的个数(节点从1开始编号)。接下来一行有n个数字,代表第i个二叉树节点的元素的值。接下来有n行,每行有一个字母Ci。
Ci=’d’表示第i个节点有两子孩子,紧接着是左孩子编号和右孩子编号。
Ci=’l’表示第i个节点有一个左孩子,紧接着是左孩子的编号。
Ci=’r’表示第i个节点有一个右孩子,紧接着是右孩子的编号。
Ci=’z’表示第i个节点没有子孩子。
输出:
对应每个测试案例,
按照前序输出其孩子节点的元素值。
若为空输出NULL。
样例输入:
7
8 6 10 5 7 9 11
d 2 3
d 4 5
d 6 7
z
z
z
z
样例输出:
8 10 11 9 6 7 5
思路分析:
求二叉树镜像的过程:先前序遍历二叉树的每个节点,如果结点有子节点,则把左右孩子结点进行对换,然后向下递归,直到第一个叶子节点结束。
二叉树每个点都会访问到一次,所以时间复杂度为O(n)。
空间复杂度O(1)。
这题算法理解了,代码好写,难而且折磨人的地方却是在测试用例和输入输出格式上。对于面试准备来说,过多拘泥于这些AC上,貌似浪费时间啊。
注意:
由于输入有数字和字符,所以要考虑输入缓冲队列的问题。如果某行含有字符则在最后会留下换行符,然后读取下一行的输入字符时,就会读取错误字符。因此在下一行数据开始输入前,要刷新缓冲区, 通过while((ch = getchar()) != ‘\n’) ; while–getchar()来吃掉前面scanf输入的’\n’。
输出格式上,输出的各节点要有一个空格,且输出最后一个元素后没有空格,而是输出一个换行符。
测试用例中,根节点是哪一个,题目并没指定,所以要根据入度来判断哪个才是根,根节点入度为0。(这里坑死我了,一直WA。潜意识里认为第一个元素就是根节点。。。。。。。)
如何根据入度来判断根节点以及构造二叉树呢:
将各个结点都看成是只有根结点而没有左右孩子的二叉树
根据各个结点之间的链接关系构造每个结点的左右孩子结点,将每个结点并入到所要构造的二叉树中;
确定根结点, 如果某个结点不是任何结点的孩子结点,则该结点就是根结点。
更详细的处理方法看代码注释!!
代码:
/********************************* 【剑指Offer面试题】 九度OJ1521:二叉树的镜像 Author:牧之丶 Date:2015年 Email:bzhou84@163.com **********************************/ #include<stdio.h> #include<stdlib.h> #include<string> #include <math.h> #include<stack> #include <vector> #include <iostream> using namespace std; #define MAX 1005 // 定义二叉树的结点 typedef struct Node { int data; Node * lchild; Node * rchild; bool isRootNode; // 标记该结点是否为根结点 }BTNode; BTNode biTNode[MAX]; // 二叉树所有结点数组 //将二叉树非叶子结点的左右孩子进行对换得到二叉树的镜像 void MirrorTree(BTNode * pNode) { if(NULL == pNode||(pNode->lchild==NULL&&pNode->rchild==NULL)) return; BTNode * temp; temp = pNode -> lchild; pNode -> lchild = pNode -> rchild; pNode -> rchild = temp; MirrorTree(pNode -> lchild); MirrorTree(pNode -> rchild); } //构造有n个结点的二叉树 BTNode * createBTree(int n) { BTNode * rootNode = NULL; //根节点 if(n==0) // 边界检查 return rootNode; char Ci; // 字符,Ci代表含有多少孩子结点的标志字符 // 二叉树结点的数据域,二叉树结点的左孩子在biTNode[]的序号和右孩子在biTNode[]的序号 int i,data,lChildNumber,rChildNumber; // 先构造,将各个结点都看成是只有根结点而没有左右孩子的二叉树 for(i = 1;i <= n;i++) { scanf("%d",&data); biTNode[i].data = data; biTNode[i].lchild = NULL; biTNode[i].rchild = NULL; biTNode[i].isRootNode = true; } // 根据各个结点之间的链接关系构造每个结点的左右孩子结点,将每个结点并入到所要构造的二叉树中 for(i = 1;i <= n;i++) { char c; while((c = getchar()) != '\n') ; //吃掉前面scanf输入那一行的'\n' scanf("%c",&Ci); switch(Ci) { case 'd': scanf("%d%d",&lChildNumber,&rChildNumber); biTNode[i].lchild = &biTNode[lChildNumber]; //定位左右孩子 biTNode[i].rchild = &biTNode[rChildNumber]; biTNode[lChildNumber].isRootNode = false; // biTNode[lChildNumber]不是二叉树的根结点 biTNode[rChildNumber].isRootNode = false; break; case 'l': scanf("%d",&lChildNumber); biTNode[i].lchild = &biTNode[lChildNumber]; biTNode[i].rchild = NULL; biTNode[lChildNumber].isRootNode = false; break; case 'r': scanf("%d",&rChildNumber); biTNode[i].lchild = NULL; biTNode[i].rchild = &biTNode[rChildNumber]; biTNode[rChildNumber].isRootNode = false; break; case 'z': biTNode[i].lchild = NULL; biTNode[i].rchild = NULL; break; default: break; } } // 如果某个结点不是任何结点的孩子结点,则该结点就是根结点 for(i = 1;i <= n;i++) { if(biTNode[i].isRootNode==true) { rootNode = &biTNode[i]; // 确定根结点 break; } } return rootNode; } //前序遍历输出二叉树 void PreOrder(BTNode * pNode) { if(pNode==NULL) return; printf(" %d",pNode -> data); //输出格式空格 PreOrder(pNode -> lchild); PreOrder(pNode -> rchild); } int main() { int n; BTNode * root; while(scanf("%d",&n)!=EOF) { root = createBTree(n); if(root == NULL) { printf("NULL\n"); } else { MirrorTree(root); printf("%d",root -> data); //输出格式 PreOrder(root -> lchild); PreOrder(root -> rchild); printf("\n"); //输出格式最后 } } return 0; } /************************************************************** Problem: 1521 Language: C++ Result: Accepted Time:0 ms Memory:1552 kb ****************************************************************/
总结
将二叉树中非叶子结点的左右孩子结点对换得到二叉树镜像。输入有数字和字符,考虑输入缓冲队列的问题。
根据入度来判断根节点的方法
相关文章推荐
- Android高薪之路-Android程序员面试宝典
- 图解程序员必须掌握的Java常用8大排序算法
- 阿拉伯数字转为中文读法
- 程序员如何爱护自己的眼睛
- 黑马程序员——Java基础语法
- 黑马程序员——JAVA基础------反射
- 毕业季,扣丁学堂送福利啦
- 面试题36_数组中的逆序对
- 黑马程序员——java中数组的定义与应用
- (面试题25题)LeetCode Path Sum II
- 面试宝典第三版第八章8.2正确程序
- 28岁程序员转行,何去何从?
- 嵌入式软件开发——嵌入式软件工程师面试题
- 写给新手程序员的一封信(转)
- 面试题35_第一个只出现一次的字符
- 面试题34_丑数
- 程序员的恋情
- 程序员如何写好技术简历 —— 实例、模板及工具
- 笔试面试
- 剑指Offer面试题11(Java版):数值的整数次方