二叉搜索树遍历 - 查找最接近的值

Posted

技术标签:

【中文标题】二叉搜索树遍历 - 查找最接近的值【英文标题】:Binary Search Tree traversal - Find Closest Value 【发布时间】:2021-12-28 20:46:09 【问题描述】:

我正在处理 AlgoExpert 挑战,我已经花时间自己解决它,观看了有关它的视频讲座,我觉得我有很好的理解,但是我的递归和树遍历技能现在相当低(这就是我正在研究它的原因)。

这是提示

编写一个接收二叉搜索树 (BST) 和目标整数的函数 值并返回最接近 BST 中包含的目标值的值。每个 BST 节点都有一个整数 value、一个 left 子节点和一个 right 子节点。它的子节点本身就是有效的 BST 节点或 None / Null

目标:12

这是我目前的解决方案:

function findClosestValueInBst(tree, target) 
    let closest = tree.value;
  const traverse = (inputTree) => 
        if (inputTree === null) return;
        if (Math.abs(target - closest) > Math.abs(target - inputTree.value)) 
            closest = inputTree.value;
        
        
        if (target < tree.value) 
            console.log('left')
            traverse(inputTree.left)
         else 
            console.log('right')
            traverse(inputTree.right)
        
        
    
    traverse(tree)
    return closest;


// This is the class of the input tree. Do not edit.
class BST 
  constructor(value) 
    this.value = value;
    this.left = null;
    this.right = null;
  

到目前为止的行为是,遍历到节点 15,但随后,它没有转到 13,而是转到 22,因此它返回 10 作为接近的可能值,而不是 13,它的绝对值比 10 更接近 12。

【问题讨论】:

您正在检查 tree 而递归函数的输入参数是 inputTree 你永远不会在函数内部返回 traverse 的结果。 @NinaScholz,他们的内部函数不返回任何内容。他们修改了一个返回的非局部变量。 据我所知,他们不需要返回traverse@NinaScholz 的结果。他们正在设置函数之外的变量。 好吧,奇怪的设计。 【参考方案1】:
function findClosestValueInBst(tree, target) 
    let closest = tree.value;
  const traverse = (inputTree) => 
        if (inputTree === null) return;
        if (Math.abs(target - closest) > Math.abs(target - inputTree.value)) 
            closest = inputTree.value;
        
        // As you can see below this line you are checking target < tree.value
        // problem is that tree is the root that your surrounding function gets
        // not the argument that your recursive function gets.
        // both your condition and your parameter to traverse
        // need to be inputTree, not tree
        if (target < tree.value) 
            console.log('left')
            traverse(inputTree.left)
         else 
            console.log('right')
            traverse(inputTree.right)
        
        
    
    traverse(tree)
    return closest;

现在看下面的代码:

function findClosestValueInBst(root, target) 
    let closest = root.value;
  const traverse = (node) => 
        if (node === null) return;
        if (Math.abs(target - closest) > Math.abs(target - node.value)) 
            closest = node.value;
        
        
        if (target < node.value) 
            console.log('left')
            traverse(node.left)
         else 
            console.log('right')
            traverse(node.right)
        
        
    
    traverse(root)
    return closest;

在这种情况下,将参数命名得更加清晰是有帮助的,这样就不会产生混淆。

【讨论】:

天哪,我看到了!我引用了错误的树。谢谢! 没问题。不客气:D【参考方案2】:

也许这行得通。

它在单个函数中检查节点,并使用具有较大初始值的最后一个值。

然后查找是否找到目标并返回目标。

否则检查目标是否在里面

function findClosestValue(tree, target, last = tree.value) 
    if (tree === null) return last;
    
    if (tree.value === target) return target;
    
    if (
        last < target && target < tree.value ||
        tree.value < target && target < last    
    ) return Math.abs(target - this.value) < Math.abs(target - last)
        ? this.value
        : last;
    
    return target < tree.value
        ? findClosestValue(tree.left, target, tree.value)
        : findClosestValue(tree.right, target, tree.value);


const
    tree =  value: 10, left:  value: 7, left:  value: 5, left: null, right: null , right:  value: 8, left: null, right: null  , right:  value: 13, left:  value: 11, left: null, right: null , right:  value: 15, left: null, right: null   ;

console.log(findClosestValue(tree, 11));
console.log(findClosestValue(tree, 12));
console.log(findClosestValue(tree, 13));
console.log(findClosestValue(tree, 14));
console.log(findClosestValue(tree, 15));
console.log(findClosestValue(tree, 16));
console.log(tree);
.as-console-wrapper  max-height: 100% !important; top: 0; 

【讨论】:

【参考方案3】:

使用 Nina Scholz 的测试用例,但我认为这是一个更简单的递归,我们可以这样做:

const closer = (v) => (x, y) => 
  Math.abs (x - v) < Math .abs (y - v) ? x : y

const findClosestValueInBst = (node, target) =>
  node == null 
    ? Infinity
  : target == node .value 
    ? node .value
  : target < node .value
    ? closer (target) (findClosestValueInBst (node .left, target), node .value)
  : closer (target) (findClosestValueInBst (node .right, target), node .value)

const tree =  value: 10, left:  value: 7, left:  value: 5, left: null, right: null , right:  value: 8, left: null, right: null  , right:  value: 13, left:  value: 11, left: null, right: null , right:  value: 15, left: null, right: null   ;

console .log (findClosestValueInBst (tree, 11))
console .log (findClosestValueInBst (tree, 12))
console .log (findClosestValueInBst (tree, 13))
console .log (findClosestValueInBst (tree, 14))
console .log (findClosestValueInBst (tree, 15))
console .log (findClosestValueInBst (tree, 16))

console .log (tree)
.as-console-wrapper max-height: 100% !important; top: 0

closer 助手只是选择两个数字中的哪个更接近目标,如果它们同样接近,则任意选择第二个。

如果提供的树是null,则主函数简单地以无限值转义,然后根据我们的target 是否等于、小于或大于当前节点的值进行分支。如果equal,我们完成并返回节点的值。如果less than,我们在左分支上递归,然后选择该结果和节点值中最接近的那个,同样,如果greater than,我们对右分支做同样的事情。

请注意,我的答案可能与 Nina 的不同,因为我们会做出不同的任意选择,例如 1113 是否更接近 12

【讨论】:

以上是关于二叉搜索树遍历 - 查找最接近的值的主要内容,如果未能解决你的问题,请参考以下文章

初探二叉搜索树

数据结构_树_二叉搜索树

BST二叉树的二分查找

树965. 单值二叉树

二叉搜索树

二叉搜索树的后序遍历序列 (剑指offer)