使用递归js查找树状对象(不是二叉树)的最低共同祖先

Posted

技术标签:

【中文标题】使用递归js查找树状对象(不是二叉树)的最低共同祖先【英文标题】:Find lowest common ancestor of tree like object (not binary tree) using recursion js 【发布时间】:2021-12-09 16:58:53 【问题描述】:

我需要一些帮助来查找树中两个节点的 Lca。那么任何人都可以解释如何使用递归遍历到某个点并返回结果。我看到了很多例子,但没有一个能真正帮助我。这种问题对我来说真的很新,我从来没有使用递归来遍历树结构。感谢任何帮助!

这就是我的树的样子,这是众多示例之一,因为它是随机生成的,而且我不能使用任何循环或 forEach,仅允许使用数组方法。

const tree = 
children: [ 
     
        children: [
             
                children: [],
                values: [15.667786122807836]
            
        ],
        values: [35.77483035532576, 1.056418140526505]
    ,
    
        children: [
            
                children: [
                    
                        children: [],
                        values: [67.83058067285563]
                    
                ],
                values: [98.89823527559626]
            
        ],
        values: [51.49890385802418, 41.85766285823911]
    ,
],
values: [6.852857017193847, 28.110428400306265, 51.385186145220494];

这就是我想要做的:

const min = graph => 
  return Math.min(...graph.values, ...graph.children.map(graphNode => min(graphNode)));
;

const max = graph => 
  return Math.max(...graph.values, ...graph.children.map(graphNode => max(graphNode)));  
;
  
const distance = graph => 
  if (!graph.children.length && !graph.values.length) return; 
     const minValue = min(graph);
     const maxValue = max(graph);
     const findPath = (graph, key1, key2) => 
  
  if (graph.values.includes(key1) || graph.values.includes(key2)) 
     return graph.values;
 ;
   
const arr = [graph.values].concat(graph.children.map(graphNode => 
  return findPath(graphNode, key1, key2);
));
    
  return arr;
;
  
  const Lca = findPath(graph, minValue, maxValue);
  return Lca;

【问题讨论】:

你能概括一下你的通用算法是什么吗?您的问题陈述说您有 2 个节点并且需要返回最低的共同祖先,但您的代码似乎做了其他事情。 所以首先我试图找到从根节点到具有最小值和最大值的每个节点的路径,如果找到了一些值,我将返回节点。其实我不知道下一步该怎么做。我正在尝试使用此处提供的解释:geeksforgeeks.org/… 但是没有类,就像上面的链接一样。我的函数也必须是纯的 对我来说最困难的部分是我的根节点有 3 个子节点,我如何才能仅返回从根节点到具有最小值或最大值的节点的路径 为什么要查找具有最小值/最大值的节点?你不是给了2个节点,你想找到他们的LCA吗?你为什么关心根到最小/最大节点路径?你的 LCA 可以是任何节点,包括根节点。我不确定你知道 2 个节点的最低共同祖先是什么。 【参考方案1】:

您的findPath 函数返回graph.values 作为基本情况,这无助于构建路径。相反,children.map 迭代的索引应该作为路径收集。

然后,当您同时拥有通向最小值的路径和通向最大值的路径时,您应该忽略它们共有的前缀,并计算表示两个极端节点之间路径上边缘的剩余部分。

这是一个可能的实现:

// the selector argument is a function that here will be either Math.min or Math.max:
function findPath(tree, selector) 
    const bestOf = (a, b) => selector(a[0], b[0]) === a[0] ? a : b;  
    const recur = (node, path) =>
        node.children.reduce((acc, child, i) => 
            bestOf(acc, recur(child, path.concat(i))),
        [selector(...node.values), path]);
    return recur(tree, [])[1];


function distanceMinMax(tree) 
    const min = findPath(tree, Math.min),
          max = findPath(tree, Math.max),
          common = min.findIndex((child, depth) => max[depth] != child);
    return min.length + max.length - (common < 0 ? min.length : common) * 2;


// Demo tree: the minimum is 1 and maximum is 10. Distance is 3.
const tree = 
    children: [ 
        children: [ 
            children: [],
            values: [3]
        ],
        values: [5, 1]
    , 
        children: [
            children: [
                children: [],
                values: [9]
            ],
            values: [10]
        ],
        values: [8, 6]
    ],
    values: [2, 4, 7]
;

console.log(distanceMinMax(tree)); // 3 

备注

你写道你...... “不能使用任何循环或forEach,只允许使用数组方法。”

这确实是一个矛盾,因为:

.forEach()数组方法; 您的代码使用.map(),这与.forEach() 非常相似; .map().includes() 都代表一个循环; 当您的数据结构包含 children 数组时,使用循环是很自然的,因为任何解决方案都必须访问此类数组的每个条目。

【讨论】:

关于您的评论:这作为家庭作业问题限制是有道理的,特别是对于课程教学递归。我不同意mapforEach 特别接近的想法。 map 具有清晰的语义。 forEach 没有。此外,mapincludes 都可以扩展到非类数组结构;因此,虽然它们可以实现用于使用循环的数组,但它们不表示循环。 先生。非常感谢您)。并感谢所有试图提供帮助的人。当然,我知道我可以使用 forEach,但由于限制,我不能使用

以上是关于使用递归js查找树状对象(不是二叉树)的最低共同祖先的主要内容,如果未能解决你的问题,请参考以下文章

二叉树中两个节点的最低公共祖节点

创建二叉树非递归完成对二叉树的先序和后序遍历并遍历输出每一层的结点数查找结点P 和结点Q的最近共同祖先

寻找二叉树中的最低公共祖先结点----LCA(Lowest Common Ancestor )问题(递归)

如果不是树中的所有这些节点,Python会在二叉树中找到两个节点的最低共同祖先

java 二叉树的最低共同祖先

如何在任何二叉树中找到两个节点的最低共同祖先?