考点:二叉树遍历,二叉树建立,多行输入,数组。
题目描述:
已知两颗二叉树,将它们合并成一颗二叉树。合并规则是:都存在的结点,就将结点值加起来,否则空的位置就由另一个树的结点来代替。例如:
两颗二叉树是:
Tree 1 :
1
/ \
3 2
/
5
Tree 2:
2
/
1 3
\
4 7
合并后的树为:
3
/
4 5
/ \
5 4 7
输入描述:
第一行输入整数n,m。(分别表示树1和树2的节点数,1<=n,m<=100)
接下来n行,第i行三个整数l,r,v, (0<=l,r<=n , 0<=v<=100) ,表示第一棵树的第i个结点的左儿子编号,右儿子编号和权值。
接下来m行,第i行三个整数l,r,v, (0<=l,r<=n , 0<=v<=100) ,表示第二棵树的第i个结点的左儿子编号,右儿子编号和权值。
(对于左右儿子,如果编号为0表示空。保证如果儿子不为空,则儿子编号大于父亲编号。)
输出描述:
输出合并后树按层遍历的各结点权值,相邻权值之间以一个空格相间。
本题在牛客网的瓜子二手车编程题中出现,首先需要控制输入,输入是由第一行的两个数字决定接下来输入的行数。所以需要首先js的多行输入。
var readline=require('readline')
const r1=readline.createInterface({
input:process.stdin,
output:process.stdout
})
var linesArrayIndex=0;
var linesArray=[];
var resultArray=[];
r1.on('line',function(line){
if(linesArrayIndex==0){
var length=line.split(' ');
var n1=length[0];
var n2=length[1];
linesArray[linesArrayIndex]=n1+n2;
//首行加入输入流队列,并表示接下来的输入行数。
}else{
linesArray[linesArrayIndex]=line;
resultArray.push(line);
}
linesArrayIndex++;
if(resultArray.length==n1+n2){
///之后对结果数组进行的操作
}
})
此时得到的输入数组是
[‘2 3 1’,‘4 0 3’,‘0 0 2’,‘0 0 5’,‘2 3 2’,‘0 4 1’,‘0 5 3’,‘0 0 4’,‘0 0 7’]
需要将这一整个数组根据两个节点个数n1和n2分割,并转换成二叉树的数据结构。
function stringtonumberarr(array){
let newarr=[];
for(let i of array){
let temparr=i.split(' ');
var newtemp=[];
for(let j of temparr){
j=parseInt(j);
newtemp.push(j);
}
newarr.push(newtemp)
}
return newarr;
}
let arr1=[];
let arr2=[];
for(let i=0;i<n1;i++){
arr1.push(resultArray[i]);
}
let arrone=stringtonumberarr(arr1);
for(let i=0;i<n2;i++){
arr2.push(resultArray[i+n1]);
}
let arrtwo=stringtonumberarr(arr2);
经过以上转换,数组元素不再为字符串而是数值型。
将处理过的数组转换为二叉树。
[ [2 ,3 ,1], [4 ,0 ,3], [0 ,0 ,2], [0 ,0 ,5] ]
我的想法是,假设数组为arr,arr[0][0]如果不为0,则表示该节点有左孩子,同理可知是否有右孩子。
将左右标记为true,若为0则为null。
然后再将节点连接,通过编号对应数组下标,找到对应的父子节点然后连接。
var inittree = function (arr) {
var pRoot=new Node(arr[0][2]);
// console.log(pRoot)
if(arr[0][0]>0){
pRoot.left=true;
}
if(arr[0][1]>0){
pRoot.right=true;
}
var nodearr=[];
nodearr.push(pRoot);
for (let i = 1; i < arr.length; i++) {
var node =new Node(arr[i][2]);
if(arr[i][0]>0){
node.left=true;
}
if(arr[i][1]>0){
node.right=true;
}
nodearr.push(node)
}
for (let j = 0; j < nodearr.length;j++) {
if(arr[j][0]!=0){
nodearr[j].left=nodearr[arr[j][0]-1]
}
if(arr[j][1]!=0){
nodearr[j].right=nodearr[arr[j][1]-1];
}
}
// console.log(pRoot)
return pRoot;
}
将两个数组转换成二叉树之后,进行二叉树合并,合并二叉树的思想是递归。思路是新建一棵树。
- 首先用两个指针同时指向两棵树的树根,然后从看是否都存在,若都存在,新建节点,其值为两个节点权值之和。若只有其中一个节点存在,则直接赋值然后连接。
- 结束该节点后再看该节点的左节点,然后再看右节点。
- 重复2步骤,进行递归。若到叶子节点则返回null,最外层返回根节点。
function mergetree(pRoot1,pRoot2){
var temp;
if(pRoot1!=null&&pRoot2!=null){
temp=new Node(pRoot1.val+pRoot2.val);
temp.left=mergetree(pRoot1.left,pRoot2.left);
temp.right=mergetree(pRoot1.right,pRoot2.right);
}else if(pRoot1==null&&pRoot2!=null){
temp=pRoot2;
}else if(pRoot1!=null&&pRoot2==null){
temp=pRoot1;
}else{
return null;
}
//console.log(temp)
return temp;
}
最后题目要求需要按层遍历输出结果
此处用的是非递归实现的按层遍历,需要用一个队列来放入每一层的节点。
function leveltraver(pRoot) {
var result=[];
var tree=[];
tree.push(pRoot);
while(tree.length){
var node=tree.shift();
result.push(node.val);
if(node.left!=null){
tree.push(node.left);
}
if(node.right!=null){
tree.push(node.right);
}
}
return result;
}
最后是完整代码:
var readline=require('readline');
const r1=readline.createInterface({
input:process.stdin,
output:process.stdout
})
var Node = function(val){
this.left=null;
this.right=null;
this.val=val;
}
function mergetree(pRoot1,pRoot2){
var temp;
if(pRoot1!=null&&pRoot2!=null){
temp=new Node(pRoot1.val+pRoot2.val);
temp.left=mergetree(pRoot1.left,pRoot2.left);
temp.right=mergetree(pRoot1.right,pRoot2.right);
}else if(pRoot1==null&&pRoot2!=null){
temp=pRoot2;
}else if(pRoot1!=null&&pRoot2==null){
temp=pRoot1;
}else{
return null;
}
//console.log(temp)
return temp;
}
var inittree = function (arr) {
var pRoot=new Node(arr[0][2]);
// console.log(pRoot)
if(arr[0][0]>0){
pRoot.left=true;
}
if(arr[0][1]>0){
pRoot.right=true;
}
var nodearr=[];
nodearr.push(pRoot);
for (let i = 1; i < arr.length; i++) {
var node =new Node(arr[i][2]);
if(arr[i][0]>0){
node.left=true;
}
if(arr[i][1]>0){
node.right=true;
}
nodearr.push(node)
}
for (let j = 0; j < nodearr.length;j++) {
if(arr[j][0]!=0){
nodearr[j].left=nodearr[arr[j][0]-1]
}
if(arr[j][1]!=0){
nodearr[j].right=nodearr[arr[j][1]-1];
}
}
// console.log(pRoot)
return pRoot;
}
function stringtonumberarr(array){
let newarr=[];
for(let i of array){
let temparr=i.split(' ');
var newtemp=[];
for(let j of temparr){
j=parseInt(j);
newtemp.push(j);
}
newarr.push(newtemp)
}
return newarr;
}
function leveltraver(pRoot) {
var result=[];
var tree=[];
tree.push(pRoot);
while(tree.length){
var node=tree.shift();
result.push(node.val);
if(node.left!=null){
tree.push(node.left);
}
if(node.right!=null){
tree.push(node.right);
}
}
return result;
}
var linesArray=[];
var linesArrayIndex=0;
var resultArray=[];
var n1,n2;
r1.on('line',function(line){
if(linesArrayIndex==0){
var length=line.split(' ');
n1=parseInt(length[0]);
n2=parseInt(length[1]);
linesArray[linesArrayIndex]=Number(length[0])+Number(length[1]);
}else{
linesArray[linesArrayIndex]=line;
}
linesArrayIndex++;
for(var i in linesArray.slice(1)){
resultArray[i]=linesArray.slice(1)[i];
}
if(resultArray.length==linesArray[0]){
//打印输出整合在数组resultArray中的输入内容
let arr1=[];
let arr2=[];
for(let i=0;i<n1;i++){
arr1.push(resultArray[i]);
}
let arrone=stringtonumberarr(arr1);
for(let i=0;i<n2;i++){
arr2.push(resultArray[i+n1]);
}
let arrtwo=stringtonumberarr(arr2);
//console.log(arrone)
//console.log(arrtwo)
var pRoot1 = inittree(arrone);
var pRoot2 = inittree(arrtwo);
var resroot=mergetree(pRoot1,pRoot2);
var ans=leveltraver(resroot);
console.log(ans.join(' '))
r1.close();
}
})