【问题标题】:Tree from balanced parenthesis平衡括号中的树
【发布时间】:2019-12-26 19:18:22
【问题描述】:

我必须找到树的高度并从平衡的括号中找到保护编号(或只是为了生成一棵树)。 例如:
()()()() 像列表一样创建树,高度为 3。
我不知道如何将括号转换为树。我找到了一些“答案”:
http://www.cs.utsa.edu/~wagner/knuth/fasc4a.pdf(第二页包含具有 4 个节点的树的所有示例)
段落 - 二叉树、森林、非交叉对:
https://sahandsaba.com/interview-question-generating-all-balanced-parentheses.html
但是,我仍然不知道如何从这样定义的括号中创建一棵树。我有一些印象,在 Knuth 中,作者将其视为显而易见的事情。
我错过了什么还是没那么简单?
有必要先造林再造二叉树吗?

【问题讨论】:

  • 您不需要创建树来计算高度。 ()()()() 用什么逻辑表示高度为 3 的树?
  • knuth 中的第二页(或纯 pdf 中的 8 页)包含具有 4 个节点的树的所有示例。
  • 包含外部链接的引用以澄清问题仍然是一个好主意。链接可能会在稍后消失,然后您的问题就没有意义了。
  • 什么是“保护号”?
  • 一棵树的保护数是从根到叶子的最短路径的长度。

标签: algorithm tree


【解决方案1】:

一对括号代表一个节点。 这些括号中出现的内容代表其左孩子的子树(根据相同的规则)。出现在这些括号右侧的内容代表节点的右孩子的子树(同样,根据相同的规则)。

这种编码到二叉树的转换可以这样递归地完成:

function makeBinaryTree(input):
    i = 0 # character index in input

    function recur():
        if i >= input.length or input[i] == ")":
            i = i + 1
            return NIL
        i = i + 1            
        node = new Node
        node.left = recur()
        if i >= input.length or input[i] == ")":
            i = i + 1
            return node
        node.right = recur()
        return node

    return recur()

下面是 JavaScript 中的一个实现,它为每个 4 节点树执行转换,并漂亮地打印结果树:

function makeBinaryTree(input) {
    let i = 0; // character index in input
    return recur();
    
    function recur() {
        if (i >= input.length || input[i++] === ")") return null;
        let node = { left: recur(), right: null };
        if (i >= input.length || input[i] === ")") {
            i++;
            return node;
        }
        node.right = recur();
        return node;
    }
}

// Helper function to pretty print a tree
const disc = "\u2B24";
function treeAsLines(node) {
    let left = [""], right = [""];
    if (node.left) left = treeAsLines(node.left);
    if (node.right) right = treeAsLines(node.right);
    while (left.length < right.length) left.push(" ".repeat(left[0].length));
    while (left.length > right.length) right.push(" ".repeat(left[0].length));
    let topLeft = "", topRight = "";
    let i = left[0].indexOf(disc);
    if (i > -1) topLeft = "┌".padEnd(left[0].length-i+1, "─");
    i = right[0].indexOf(disc);
    if (i > -1) topRight = "┐".padStart(i+2, "─");
    return [topLeft.padStart(left[0].length+1) + disc + topRight.padEnd(right[0].length+1)]
           .concat(left.map((line, i) => line + "   " + right[i]));
}

// The trees as listed in Table 1 of http://www.cs.utsa.edu/~wagner/knuth/fasc4a.pdf
let inputs = [
    "()()()()",
    "()()(())",
    "()(())()",
    "()(()())",
    "()((()))",
    "(())()()",
    "(())(())",
    "(()())()",
    "(()()())",
    "(()(()))",
    "((()))()",
    "((())())",
    "((()()))",
    "(((())))"
];

for (let input of inputs) {
    let tree = makeBinaryTree(input);
    console.log(input);
    console.log(treeAsLines(tree).join("\n"));
}

【讨论】:

    【解决方案2】:

    如果我对 Knuth 的理解正确,则表示如下:一对匹配的括号表示一个节点,例如() = A. 两对连续的匹配括号意味着第二个节点是第一个节点的右孩子,例如()() = A -> B。而两对内嵌括号表示内节点是外节点的左子节点,即(()) = B B -> C -> D.

    将括号转换为二叉树的可能算法是:

    convert(parentheses):
      if parentheses is empty:
        return Nil
    
      root = Node()
    
      left_start = 1
      left_end = Nil
    
      open = 0
      for p = 0 to |parentheses|-1:
        if parentheses[p] == '(':
          open += 1
        else
          open -= 1
    
        if open == 0:
          left_end = p
          break
    
      root.left = convert(parentheses[left_start:left_end] or empty if index out of bound)
      root.right = convert(parentheses[left_end+1:] or empty if index out of bound)
    
      return root
    

    它的工作原理是递归地转换二叉树 L R 中的括号 (L)R。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-05
      • 2015-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多