FernFlower:Java字节码逆向工程的深度解析与实现原理揭秘
2026/4/30 11:41:16
目录
一、方法一:递归边界约束法(范围校验)
1. 核心思想
2. 完整实现代码
3. 重点 & 难点
二、方法二:中序遍历法(利用 BST 特性)
1. 核心思想
2. 实现代码
版本 1:递归中序遍历(简洁易理解)
版本 2:迭代中序遍历(避免递归栈溢出)
3. 重点 & 难点
三、两种方法对比
四、常见易错点总结
五、总结
验证二叉搜索树(BST)是二叉树高频面试题,核心考点是准确理解 BST 的定义(左子树所有节点值 <根节点值,右子树所有节点值> 根节点值,且左右子树也必须是 BST),而非仅 “根节点大于左孩子、小于右孩子”。以下总结两种主流解法,涵盖核心思想、实现、重点难点及对比。
基于 BST 的定义,为每个节点划定合法取值范围(左边界 < 节点值 < 右边界):
(Long.MIN_VALUE, Long.MAX_VALUE)(用 Long 避免 int 极值溢出);class Solution { // 递归函数:校验当前节点是否在(left, right)范围内,且子树满足BST private boolean isValidBSTHelper(TreeNode root, long left, long right) { if (root == null) return true; // 空树是合法BST long curVal = root.val; // 核心:当前节点超出范围 → 不合法;递归校验左右子树 if (curVal <= left || curVal >= right) return false; return isValidBSTHelper(root.left, left, curVal) // 左子树范围:(left, curVal) && isValidBSTHelper(root.right, curVal, right); // 右子树范围:(curVal, right) } public boolean isValidBST(TreeNode root) { // 初始范围用Long极值,避免int最大值/最小值的溢出问题 return isValidBSTHelper(root, Long.MIN_VALUE, Long.MAX_VALUE); } }注:个人暂时感觉这个思路好理解一点;很多方法其实只需要记一种,然后面试的时候思路清晰就OK
Long类型替代int作为边界,解决Integer.MAX_VALUE/Integer.MIN_VALUE作为节点值时的校验失效问题(如测试用例[2147483647])。Integer极值,导致极端值校验失败;BST 的核心特性:中序遍历结果是严格递增的序列(左→根→右,值从小到大)。
class Solution { private long preVal = Long.MIN_VALUE; // 记录前一个节点值,初始为Long最小值 public boolean isValidBST(TreeNode root) { // 中序遍历:左→根→右 if (root == null) return true; // 先遍历左子树,左子树不合法直接返回false if (!isValidBST(root.left)) return false; // 校验当前节点:若≤前一个值,不合法 if (root.val <= preVal) return false; // 更新前一个节点值为当前值;注意此处应该递归到了最底层,从左子树最下面的节点开始的 preVal = root.val; // 遍历右子树 return isValidBST(root.right); } }class Solution { public boolean isValidBST(TreeNode root) { if (root == null) return true; Deque<TreeNode> stack = new LinkedList<>(); long preVal = Long.MIN_VALUE; TreeNode cur = root; // 迭代中序遍历模板 while (cur != null || !stack.isEmpty()) { // 先遍历左子树,全部入栈 while (cur != null) { stack.push(cur); cur = cur.left; } // 弹出栈顶(当前最左节点) cur = stack.pop(); // 校验递增性 if (cur.val <= preVal) return false; preVal = cur.val; // 遍历右子树 cur = cur.right; } return true; } }preVal需设为Long.MIN_VALUE,避免节点值为Integer.MIN_VALUE时误判。preVal的作用域(需设为成员变量 / 数组传递,避免递归栈覆盖);| 方法 | 时间复杂度 | 空间复杂度 | 核心优势 | 适用场景 |
|---|---|---|---|---|
| 递归边界约束法 | O(n) | O(h) | 直接贴合 BST 定义,逻辑严谨 | 需快速验证、递归深度可控 |
| 中序遍历法(递归) | O(n) | O(h) | 利用 BST 特性,代码简洁 | 面试中快速手写、逻辑直观 |
| 中序遍历法(迭代) | O(n) | O(h) | 避免递归栈溢出 | 处理深度极大的二叉树 |
(注:n 为节点数,h 为树的高度;平衡树 h=logn,斜树 h=n)
int而非Long作为边界 / 前值,导致Integer.MAX_VALUE/Integer.MIN_VALUE测试用例失效;[5,1,4,null,null,3,6]会误判为合法);