二叉搜索树相关问题

1.验证二叉搜索树

解法一 中序遍历非递归实现 1ms

public boolean isValidBST(TreeNode node) {
    TreeNode p = node;
    LinkedList<TreeNode> stack = new LinkedList<>();
    long prev = Long.MIN_VALUE; // 代表上一个值
    while (p != null || !stack.isEmpty()) {
        if (p != null) {
            stack.push(p);
            p = p.left;
        } else {
            TreeNode pop = stack.pop();
            // 处理值
            // System.out.println("compare:" + prev + " " + pop.val);
            if (prev >= pop.val) {
                return false;
            }
            prev = pop.val;
            p = pop.right;
        }
    }
    return true;
}

 

中序遍历递归实现(全局变量记录 prev) 0ms

// 解法2. 中序遍历递归实现(全局变量记录 prev) 0ms
long prev = Long.MIN_VALUE;
public boolean isValidBST(TreeNode node) {
    if (node == null) {
        return true;
    }
    boolean a = isValidBST(node.left);
    if (!a) {
        return false;
    }
    if (prev >= node.val) {
        return false;
    }
    prev = node.val;
    return isValidBST(node.right);
}

 

 中序遍历递归实现(局部变量记录 prev,方法内的局部变量变化无效,所以使用对象) 0ms

public boolean isValidBST(TreeNode node) {
    return doValid3(node, new AtomicLong(Long.MIN_VALUE));
}
private boolean doValid3(TreeNode node, AtomicLong prev) {
    if (node == null) {
        return true;
    }
    boolean a = doValid3(node.left, prev);
    if (!a) {
        return false;
    }
    if (prev.get() >= node.val) {
        return false;
    }
    prev.set(node.val);
    return doValid3(node.right, prev);
}

 

上下限递归实现 0ms

doValid4,接受三个参数:当前节点 node、当前节点允许的最小值 min、当前节点允许的最大值 max。递归地对左子树和右子树进行验证,更新相应的上下限:对于左子树,更新最大值为当前节点的值;对于右子树,更新最小值为当前节点的值。

public boolean isValidBST(TreeNode node) {
    return doValid4(node, Long.MIN_VALUE, Long.MAX_VALUE);
}

private boolean doValid4(TreeNode node, long min, long max){
    if (node == null) {
        return true;
    }
    if (node.val <= min || node.val >= max) {
        return false;
    }
    return doValid4(node.left, min, node.val) && doValid4(node.right, node.val, max);
}

 

2.二叉搜索树的范围和

中序遍历非递归实现 4ms
public int rangeSumBST1(TreeNode node, int low, int high) {
    TreeNode p = node;
    LinkedList<TreeNode> stack = new LinkedList<>();
    int sum = 0;
    while(p != null || !stack.isEmpty()) {
        if (p != null) {
            stack.push(p);
            p = p.left;
        } else {
            TreeNode pop = stack.pop();
            // 处理值
            if (pop.val > high) {
                break;
            }
            if (pop.val >= low) {
                sum += pop.val;
            }
            p = pop.right;
        }
    }
    return sum;
}

 

上下限递归 0ms

public int rangeSumBST(TreeNode node, int low, int high) {
    if (node == null) {
        return 0;
    }
    if (node.val < low) {
        return rangeSumBST(node.right, low, high);
    }
    if (node.val > high) {
        return rangeSumBST(node.left, low, high);
    }
    // 在范围内
    return node.val + rangeSumBST(node.left, low, high) + rangeSumBST(node.right, low, high);
}

 

 

3.前序遍历构造二叉搜索树

insert 方法是一个递归方法,用于将给定的值 val 插入到以 node 为根节点的二叉搜索树中。如果当前节点为空(即 node == null),则直接创建一个新节点并返回。如果 val 小于当前节点的值,则递归地将 val 插入到左子树中;如果 val 大于当前节点的值,则递归地将 val 插入到右子树中。最后返回当前节点 node。
最后返回构建好的 BST 的根节点 root。

public TreeNode bstFromPreorder(int[] preorder) {
    TreeNode root = insert(null, preorder[0]);
    for (int i = 1; i < preorder.length; i++) {
        insert(root, preorder[i]);
    }
    return root;
}

private TreeNode insert(TreeNode node, int val) {
    if (node == null) {
        return new TreeNode(val);
    }
    if(val < node.val) {
        node.left = insert(node.left, val);
    } else if(node.val < val){
        node.right = insert(node.right, val);
    }
    return node;
}

 

使用上限法(最优)构建二叉搜索树,使用了一个成员变量 index 来追踪前序遍历数组的当前位置,并根据上限值来确定节点的位置。在每次递归调用时,我们将当前值与上限值进行比较,以决定是否继续构建左子树或右子树。

private int index = 0;

public TreeNode bstFromPreorder(int[] preorder) {
    return bstFromPreorder(preorder, Integer.MAX_VALUE);
}

private TreeNode bstFromPreorder(int[] preorder, int upper) {
    if (index == preorder.length || preorder[index] > upper) {
        return null;
    }

    TreeNode root = new TreeNode(preorder[index++]);
    root.left = bstFromPreorder(preorder, root.val);
    root.right = bstFromPreorder(preorder, upper);

    return root;
}

如果当前位置超过数组长度或者当前节点的值大于上限值,那么返回 null。否则,创建一个节点,并递增 index,然后递归构建左子树和右子树,分别将当前节点的值作为左子树的上限值。

 

使用分治法构建二叉搜索树时,通过递归地将问题分解成更小的子问题,然后将子问题的解合并起来得到最终的结果。

public TreeNode bstFromPreorder(int[] preorder) {
    return constructBST(preorder, 0, preorder.length - 1);
}

private TreeNode constructBST(int[] preorder, int start, int end) {
    if (start > end) {
        return null;
    }

    TreeNode root = new TreeNode(preorder[start]);
    int i;
    for (i = start + 1; i <= end; i++) {
        if (preorder[i] > root.val) {
            break;
        }
    }

    root.left = constructBST(preorder, start + 1, i - 1);
    root.right = constructBST(preorder, i, end);

    return root;
}

 

4.二叉搜索树的最近公共祖先

使用 while 循环来不断迭代找到最近公共祖先。

  • 循环条件是:当节点 p 和节点 q 都在当前节点 a 的同一侧时,继续循环。
  • 在循环中,通过比较节点 p 和节点 q 的值与当前节点 a 的值,来确定它们是否在同一侧。如果都小于当前节点的值或者都大于当前节点的值,则它们在同一侧。
  • 根据节点 p 和节点 q 的值与当前节点 a 的值的比较结果,更新当前节点 a 为其左子节点或右子节点,以便继续向下搜索。
  • 当节点 p 和节点 q 不在同一侧时,循环结束,返回当前节点 a,即为节点 p 和节点 q 的最近公共祖先。

代码如下

public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    TreeNode a = root;
    while (p.val < a.val && q.val < a.val || a.val < p.val && a.val < q.val) { // 在同一侧
        if (p.val < a.val) {
            a = a.left;
        } else {
            a = a.right;
        }
    }
    return a;
}

 

 

参考

98. 验证二叉搜索树 – 力扣(LeetCode)

938. 二叉搜索树的范围和 – 力扣(LeetCode)

1008. 前序遍历构造二叉搜索树 – 力扣(LeetCode)

235. 二叉搜索树的最近公共祖先 – 力扣(LeetCode)

黑马数据结构

暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇