Leetcode刷题系列(五)Binary Search Tree相关

本文深入探讨了二叉搜索树的基本概念及其多种典型应用场景,包括验证二叉搜索树的有效性、实现二叉搜索树迭代器、删除节点及在特定范围内查找节点等,并提供了具体的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  Binary Search Tree是一种搜索的数据结构,它的定义为:它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

  本篇将展开一些Binary Search Tree的相关题型。
  


Validate Binary Search Tree

题目

  验证是否为一颗二叉排序树。

思路

  此题使用二叉排序树的定义即可,有两种方式:

  • 中序遍历,检查每个节点是否按大小进行排布,同时左右子树是否为二叉排序树。
  • 使用分治法,定义一个数据类存储子树中的最大值和最小值检查节点的顺序是否规范,同时检查左右子树是否为二叉排序树。

      上述两种方法均为递归方法,因为同时要检验左右子树是否二叉排序树。

代码

  这里只给出分治法的代码:

public boolean isValidBST(TreeNode root) {
    ResultType r = validateHelper(root);
    return r.is_bst;
}

private ResultType validateHelper(TreeNode root) {
    if (root == null) {
        return new ResultType(true, Integer.MIN_VALUE, Integer.MAX_VALUE);
    }

    ResultType left = validateHelper(root.left);
    ResultType right = validateHelper(root.right);

    if (!left.is_bst || !right.is_bst) {
        // if is_bst is false then minValue and maxValue are useless
        return new ResultType(false, 0, 0);
    }

    if (root.left != null && left.maxValue >= root.val || 
          root.right != null && right.minValue <= root.val) {
        return new ResultType(false, 0, 0);
    }

    return new ResultType(true,
                          Math.max(root.val, right.maxValue),
                          Math.min(root.val, left.minValue));
}

Binary Search Tree Iterator

题目

  设计实现一个带有下列属性的二叉排序树的迭代器:

  • 元素按照递增的顺序被访问
  • next()和hasNext()的询问操作要求均摊时间复杂度是O(1)

思路

  根据二叉排序树的定义,按递增的顺序被访问的遍历是中序遍历。而next()和hasNext()的均摊复杂度为O(1),则需要一个栈来记忆部分访问过的节点。

代码

public class BSTIterator {
    private Stack<TreeNode> stack = new Stack<>();
    private TreeNode curt;

    public BSTIterator(TreeNode root) {
        curt = root;
    }

    public boolean hasNext() {
        return (curt != null || !stack.isEmpty());
    }

    public TreeNode next() {
        while (curt != null) {
            stack.push(curt);
            curt = curt.left;
        }

        curt = stack.pop();
        TreeNode node = curt;
        curt = curt.right;

        return node;
    }
}

  
  next()中的代码基本为中序遍历的代码,只是将已遍历过的节点进行存储使得均摊复杂度为O(1)。
  


Remove Node in Binary Search Tree

题目

  题目为删除二叉排序树中的一个节点。

思路

  首先,我们要找到这个节点。其次,重要的是把删除该节点的二叉树恢复成二叉排序树,这也是最关键和困难的一步。如果该节点没有子树,那么不需要恢复;如果该节点只有左子树或右子树,那么使用左子树或右子树的根节点直接代替该节点;如果该节点有两个子树,那么使用右子树中最小值节点(该节点没有左子树)进行代替即可,右子树最小值节点为第一个大于该节点的节点,所以这样做不会破坏二叉排序树的结构。

代码

  这里只给出删除节点进行恢复的代码:

private void deleteNode(TreeNode parent, TreeNode node) {
    if (node.right == null) {
        if (parent.left == node) {
            parent.left = node.left;
        } else {
            parent.right = node.left;
        }
    } else {
        TreeNode temp = node.right;
        TreeNode father = node;

        while (temp.left != null) {
            father = temp;
            temp = temp.left;
        }

        if (father.left == temp) {
            father.left = temp.right;
        } else {
            father.right = temp.right;
        }

        if (parent.left == node) {
            parent.left = temp;
        } else {
            parent.right = temp;
        }

        temp.left = node.left;
        temp.right = node.right;
    }
}

  右子树中最小值节点为最左边的值。
  


Search Range in Binary Search Tree

题目

  给定两个值,求二叉排序树中值范围在这两个值中的节点。

思路

  此题目用递归来实现。

代码

public ArrayList<Integer> searchRange(TreeNode root, int k1, int k2) {
    results = new ArrayList<Integer>();
    helper(root, k1, k2);
    return results;
}

private void helper(TreeNode root, int k1, int k2) {
    if (root == null) {
        return;
    }
    if (root.val > k1) {
        helper(root.left, k1, k2);
    }
    if (root.val >= k1 && root.val <= k2) {
        results.add(root.val);
    }
    if (root.val < k2) {
        helper(root.right, k1, k2);
    }
}

  上述代码根据二叉排序树的定义,如果当前节点的值大于k1则在该节点的左子树中进行搜索,如果当前节点的值小于k2则在该节点的右子树进行搜索,如果在此范围之外则不进行任何操作直接结束。

### LeetCode入门与基础知识 对于初学者而言,在LeetCode的主要目的是通过实际操作来巩固和加深对数据结构和算法的理解[^1]。因此,了解一些基础概念以及合理的学习路径是非常重要的。 #### 数据结构基础 以下是几种常见的数据结构及其应用场景: - **数组 (Array)** 数组是最简单的线性数据结构之一,支持随机访问元素。它适用于需要频繁读取固定位置元素的场景[^2]。 - **链表 (Linked List)** 链表是一种动态分配内存的数据结构,适合于频繁插入和删除节点的操作。单向链表、双向链表和循环链表是其常见变体。 - **栈 (Stack)** 和 **队列 (Queue)** 栈遵循后进先出(LIFO)原则,常用于括号匹配等问;队列则采用先进先出(FIFO),可用于广度优先搜索(BFS)。 - **哈希表 (Hash Table)** 哈希表提供快速查找功能,时间复杂度通常为O(1)。它是解决两数之和(Two Sum)这类问的核心工具。 - **树 (Tree)** 包括二叉树、平衡树(如AVL树)、红黑树(Red-Black Tree)、B/B+树等。它们广泛应用于文件系统索引、数据库查询优化等领域。 - **Trie树 (Prefix Tree)** Trie树特别擅长处理字符串前缀相关的问,例如字典单词检索或自动补全功能实现。 #### 算法初步 除了熟悉上述各种数据结构外,还需掌握若干经典算法: - 排序算法:冒泡排序、选择排序、插入排序属于简单但效率较低的方法;而快速排序(Quick Sort)、归并排序(Merge Sort)则是更高效的替代方案。 ```python def quick_sort(arr): if len(arr) <= 1: return arr else: pivot = arr[len(arr)//2] left = [x for x in arr if x < pivot] middle = [x for x in arr if x == pivot] right = [x for x in arr if x > pivot] return quick_sort(left)+middle+quick_sort(right) ``` - 查找算法:二分查找(Binary Search)是在有序列表中高效定位目标项的有效手段。 - 动态规划(Dynamic Programming, DP): 解决最优化问的强大技术,核心在于状态转移方程的设计。 #### 学习策略 制定合理的计划有助于提高学习效果: - 结合理论知识与实战练习同步推进; - 定期回顾已学内容以强化记忆; - 参考高质量资料如《LeetCode开源手册》获取更多技巧[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值