这是一道亚马逊面试题。有没有人能给出一个算法来实现呢?
有一棵二叉树,具有以下特点:
- 所有内部节点的值都为
'N'
,所有叶子节点的值都为'L'
。 - 每个节点要么有两个孩子,要么没有孩子。
给定它的前序遍历,构造该树并返回根节点。
这是一道亚马逊面试题。有没有人能给出一个算法来实现呢?
有一棵二叉树,具有以下特点:
'N'
,所有叶子节点的值都为'L'
。给定它的前序遍历,构造该树并返回根节点。
由于每个内部节点都有两个孩子,我们可以使用递归构建树。
我们使用提供的输入调用函数,并检查它获取的第一个字符。如果它是叶节点,它只返回一个叶节点。如果它是内部节点,它只为左右子树调用自身,并返回以该节点为根节点、以左右子树作为其左右孩子形成的树。
以下是代码(Python)。请注意,我使用元组表示节点,因此树是元组的元组。
#! /usr/bin/env python
from collections import deque
def build_tree(pre_order):
root=pre_order.popleft()
if root=='L':
return root
else:
return (root,build_tree(pre_order),build_tree(pre_order))
if __name__=='__main__':
print build_tree(deque("NNLLL"))
编辑:Java代码
import java.util.*;
class Preorder{
public static Node buildTree(List<Character> preorder){
char token=preorder.remove(0);
if (token=='L'){
return new Node(token,null,null);
}
else{
return new Node(token,buildTree(preorder),buildTree(preorder));
}
}
public static void main(String args[]){
List<Character> tokens=new LinkedList<Character>();
String input="NNLLL";
for(int i=0;i<input.length();i++) tokens.add(input.charAt(i));
System.out.println(buildTree(tokens));
}
}
class Node{
char value;
Node left,right;
public Node(char value, Node left, Node right){
this.value=value;
this.left=left;
this.right=right;
}
public String toString(){
if (left==null && right==null){
return "("+value+")";
}
else{
return "("+value+", "+left+", "+right+")";
}
}
}
我认为关键是要意识到相邻节点有三种可能性:NN、NL?、L?(“?”表示N或L)
使用STACK是因为当我们在先序序列中读取一个节点时,我们不知道它的右子节点在哪里(只要它有左子节点,我们就知道它的左子节点在哪里)。STACK存储此节点,以便当其右子节点出现时,我们可以弹出它并完成其右链接。
NODE * preorder2tree(void)
{
NODE * head = next_node();
NODE * p = head;
NODE * q;
while (1) {
q = next_node();
if (!q)
break;
/* possibilities of adjacent nodes:
* NN, NL?, L?
*/
if (p->val == 'N') {
p->L = q;
if (q->val == 'N') { /* NN */
push(p);
p = q;
} else { /* NL? */
q = next_node();
p->R = q;
p = q;
}
} else { /* L? */
p = pop();
p->R = q;
p = q;
}
}
return head;
}
上面的代码已经使用一些简单的案例进行了测试。希望它是正确的。
static Stack<node> stk = new Stack<node>();
static node root=null;
static class node
{
char value;
node left;
node right;
public node(char value)
{
this.value=value;
this.left=null;
this.right=null;
}
}
public static node stkoper()
{
node posr=null,posn=null,posl=null;
posr=stk.pop();
if(stk.empty())
{
stk.push(posr);
return null;
}
else
posl=stk.pop();
if(stk.empty())
{
stk.push(posl);
stk.push(posr);
return null;
}
else
{
posn=stk.pop();
}
if( posn.value == 'N' && posl.value == 'L' && posr.value == 'L')
{
root = buildtree(posn, posl, posr);
if(stk.empty())
{
return root;
}
else
{
stk.push(root);
root=stkoper();
}
}
else
{
stk.push(posn);
stk.push(posl);
stk.push(posr);
}
return root;
}
public static node buildtree(node posn,node posl,node posr)
{
posn.left=posl;
posn.right=posr;
posn.value='L';
return posn;
}
public static void inorder(node root)
{
if(root!=null)
{
inorder(root.left);
if((root.left == null) && (root.right == null))
System.out.println("L");
else
System.out.println("N");
inorder(root.right);
}
}
public static void main(String args[]){
String input="NNNLLLNLL";
char[] pre = input.toCharArray();
for (int i = 0; i < pre.length; i++)
{
node temp = new node(pre[i]);
stk.push(temp);
root=stkoper();
}
inorder(root);
}
}
构造函数执行实际的树构建。代码片段是上述你提到的GeeksforGeeks问题的解决方案。
struct Node*construct(int &index, Node*root, int pre[], int n, char preLN[])
{
Node*nodeptr;
if(index==n)
{
return NULL;
}
if(root==NULL)
{
nodeptr = newNode(pre[index]);
}
if(preLN[index]=='N')
{
index = index+1;
nodeptr->left = construct(index, nodeptr->left, pre,n,preLN);
index = index+1;
nodeptr->right = construct(index, nodeptr->right,pre,n,preLN);
return nodeptr;
}
return nodeptr;
}
struct Node *constructTree(int n, int pre[], char preLN[])
{
int index =0;
Node*root = construct(index,NULL,pre,n,preLN);
return root;
}
注意事项:
已将Index声明为引用变量,因此在返回到父节点时,函数从最新的Index值开始构建树,而不是初始执行调用时函数所拥有的Index值。
右子树和左子树具有不同的Index值,因为前序遍历遵循根、左、右的节点顺序。
希望对您有所帮助。
我可以想到一个递归算法。
head
= 新节点。
从 preorderString
中删除第一个字符
调用 f(head, preorderString)
递归函数 f(node, s)
- 从 s 中删除第一个字符,如果是 L
,则将其作为叶子节点附加到 node 上。
否则创建一个 nodeLeft,将其附加到 node 上,调用 f(nodeLeft, s)
- 从 s 中删除第一个字符,如果是 L
,则将其作为叶子节点附加到 node 上。
否则创建一个 nodeRight,将其附加到 node 上,调用 f(nodeRight, s)