当前位置:   article > 正文

二叉搜索树(BST)合集_bst性质

bst性质

目录

一、BST定义和性质

二、二叉搜索树中第K小的元素

三、把二叉搜索树转换为累加树

四、合法二叉搜索树

五、二叉搜索树中的搜索

六、二叉搜索树中的插入操作

七、在 BST 中删除一个数

八、不同的二叉搜索树

 九、不同的二叉搜索树 II


一、BST定义和性质

定义:BST是一棵空树,或者具有以下性质的二叉树

性质:

  • 若它的左子树不空,则左子树的所有节点值都小于根节点的值
  • 若它的右子树不空,则右子树的所有节点值都大于根节点的值
  • 左子树和右子树都是二叉搜索树

备注:BST中序遍历是升序序列

根据以上性质,下面介绍相关BST题型

二、二叉搜索树中第K小的元素

题目:给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 1 开始计数)。

示例 1:

输入:root = [3,1,4,null,2], k = 1
输出:1
示例 2:

 
输入:root = [5,3,6,2,4,null,null,1], k = 3
输出:3

分析:

  • 根据BST中序遍历为升序序列,则该题进行中序遍历,遍历到第K个节点即可

示例代码:

  1. int nRet = 0;
  2. int nIndex = 0;
  3. void help(TreeNode* root,int k)
  4. {
  5. if (root == nullptr)
  6. {
  7. return ;
  8. }
  9. if (root->left != nullptr)
  10. {
  11. help(root->left,k);
  12. }
  13. nIndex++;
  14. if (k == nIndex)
  15. {
  16. nRet = root->val;
  17. return ;
  18. }
  19. // vecNum.push_back(root->val);
  20. if (root->right != nullptr)
  21. {
  22. help(root->right,k);
  23. }
  24. }
  25. int kthSmallest(TreeNode* root, int k) {
  26. help(root,k);
  27. return nRet;
  28. }

三、把二叉搜索树转换为累加树

题目:给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。

示例 1:

 输入:[4,1,6,0,2,5,7,null,null,null,3,null,null,null,8]
输出:[30,36,21,36,35,26,15,null,null,null,33,null,null,null,8]
示例 2:

输入:root = [0,null,1]
输出:[1,null,1]
示例 3:

输入:root = [1,0,2]
输出:[3,3,2]
示例 4:

输入:root = [3,2,4,1]
输出:[7,9,4,10]

分析:

  • 虽然BST中序遍历是升序序列,但是当前节点的父节点也比本身大,并且获取不到父节点
  • 所以我们还是根据中序遍历的性质,先遍历右子树,在遍历左子树,成为降序序列

示例代码:

  1. TreeNode* convertBST(TreeNode* root) {
  2. help(root);
  3. return root;
  4. }
  5. int nSum = 0;
  6. void help(TreeNode* root)
  7. {
  8. if (root == nullptr)
  9. {
  10. return;
  11. }
  12. help(root->right);
  13. nSum += root->val;
  14. root->val = nSum;
  15. help(root->left);
  16. }

四、合法二叉搜索树

题目:实现一个函数,检查一棵二叉树是否为二叉搜索树。

示例 1:
输入:
    2
   / \
  1   3
输出: true
示例 2:
输入:
    5
   / \
  1   4
     / \
    3   6
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
     根节点的值为 5 ,但是其右子节点值为 4 

分析:

  • 根据BST左子树大于右子树性质,我们很容易写出如下代码:

boolean isValidBST(TreeNode root) {
    if (root == null) return true;
    if (root.left != null && root.val <= root.left.val)
        return false;
    if (root.right != null && root.val >= root.right.val)
        return false;
    return isValidBST(root.left)
        && isValidBST(root.right);
}

但是看如图:

符合上面的代码,缺不是一棵二叉搜索树 ,因为我们只检查了该节点的左右子节点,但是BST性质是左右子树。

  • 我们可以增加两个变量,存储最大值和最小值节点

示例代码:

  1. bool isValidBST(TreeNode* root) {
  2. return help(root,nullptr,nullptr);
  3. }
  4. bool help(TreeNode* root,TreeNode* max,TreeNode* min)
  5. {
  6. if (root == nullptr)
  7. {
  8. return true;
  9. }
  10. if (max != nullptr && root->val >= max->val)
  11. {
  12. return false;
  13. }
  14. if (min != nullptr && root->val <= min->val)
  15. {
  16. return false;
  17. }
  18. return help(root->right,max,root) && help(root->left,root,min);
  19. }

五、二叉搜索树中的搜索

题目:给定二叉搜索树(BST)的根节点和一个值。 你需要在BST中找到节点值等于给定值的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 NULL。

例如,

给定二叉搜索树:

        4
       / \
      2   7
     / \
    1   3

和值: 2
你应该返回如下子树:

      2     
     / \   
    1   3

分析:

  • 根据BST性质,如果root->val == val则返回root
  • 如果root->val > val,则遍历左子树
  • 如果root->val < val,则遍历右子树

示例代码:

  1. TreeNode* searchBST(TreeNode* root, int val) {
  2. return help(root,val);
  3. }
  4. TreeNode * help(TreeNode* root, int val)
  5. {
  6. if (root == nullptr)
  7. {
  8. return nullptr;
  9. }
  10. if (root->val == val)
  11. {
  12. return root;
  13. }
  14. else if (root->val > val)
  15. {
  16. return help(root->left,val);
  17. }
  18. else if (root->val < val)
  19. {
  20. return help(root->right,val);
  21. }
  22. return nullptr;
  23. }

六、二叉搜索树中的插入操作

题目:给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。

注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。

示例 1:

 输入:root = [4,2,7,1,3], val = 5
输出:[4,2,7,1,3,5]
解释:另一个满足题目要求可以通过的树是:

 示例 2:

输入:root = [40,20,60,10,30,50,70], val = 25
输出:[40,20,60,10,30,50,70,null,null,25]
示例 3:

输入:root = [4,2,7,1,3,null,null,null,null,null,null], val = 5
输出:[4,2,7,1,3,5]

分析:

 

示例代码:

  1. TreeNode* insertIntoBST(TreeNode* root, int val) {
  2. return help(root,val);
  3. }
  4. TreeNode * help(TreeNode* root, int val)
  5. {
  6. if (root == nullptr)
  7. {
  8. root = new TreeNode(val);
  9. }
  10. if (root->val > val)
  11. {
  12. root->left = help(root->left,val);
  13. }
  14. else if(root->val < val)
  15. {
  16. root->right = help(root->right,val);
  17. }
  18. return root;
  19. }

七、在 BST 中删除一个数

题目:给定一个BST和一个目标数,将该节点删除。

例如:

 分析:

  • 根据BST性质,很容易找到要删除的节点A
  • 删除节点A分如下三种情况讨论
  1. A的左右节点都为空,如题示例,则:
        if (root.left == null && root.right == null)                                                                            return null;
  2. A只有一个非空子节点,那么要让这个孩子节点接替自己位置,如图:if (root.left == null) return root.right;
    if (root.right == null) return root.left;
  3. A有两个非空子节点,为了不破坏BST性质,A必须找到左子树中最大的那个节点,或者右子树最小的那个节点接替自己位置,如图:

      if (root.left != null && root.right != null) {//以找右子树最小值为例
              // 找到右子树的最小节点
             TreeNode minNode = getMin(root.right);
             // 把 root 改成 minNode
             root.val = minNode.val;
             // 转而去删除 minNode
             root.right = deleteNode(root.right, minNode.val);
        }

 示例代码:

  1. TreeNode* deleteNode(TreeNode *root, int key) {
  2. if (root == nullptr)
  3. {
  4. return nullptr;
  5. }
  6. if (root->val == key) {
  7. // 这两个 if 把情况 1 和 2 都正确处理了
  8. if (root->left == nullptr)
  9. {
  10. return root->right;
  11. }
  12. if (root->right == nullptr)
  13. {
  14. return root->left;
  15. }
  16. // 处理情况 3
  17. TreeNode* minNode = getMin(root->right);
  18. root->val = minNode->val;
  19. root->right = deleteNode(root->right, minNode->val);
  20. }
  21. else if (root->val > key)
  22. {
  23. root->left = deleteNode(root->left, key);
  24. }
  25. else if (root->val < key)
  26. {
  27. root->right = deleteNode(root->right, key);
  28. }
  29. return root;
  30. }
  31. TreeNode* getMin(TreeNode* node) {
  32. // BST 最左边的就是最小的
  33. while (node->left != nullptr)
  34. {
  35. node = node->left;
  36. }
  37. return node;
  38. }

八、不同的二叉搜索树

题目:给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。

示例 1:

输入:n = 3
输出:5
示例 2:

输入:n = 1
输出:1

分析:

  • 根节点可以有n种选择
  • 比如n = 5,选择3为根节点,则{1,2}就是左子树组合,{4,5}就是右子树组合
  • 左右子树组合乘积就是以3为根节点的BST种数

示例代码:

  1. //备忘录消除一下重复子项
  2. int numTrees(int n) {
  3. vector<vector<int>> memo(n + 1, vector<int>(n + 1,0));
  4. return help(1,n,memo);
  5. }
  6. int help(int nLow, int nHeight,vector<vector<int>> &memo)
  7. {
  8. if (nLow > nHeight)
  9. {
  10. return 1;
  11. }
  12. if (memo[nLow][nHeight] != 0)
  13. {
  14. return memo[nLow][nHeight];
  15. }
  16. int ret = 0;
  17. for (int i = nLow; i <= nHeight; i++)
  18. {
  19. //以i为根节点
  20. int nLeft = help(nLow, i - 1,memo);
  21. int nRight = help(i + 1, nHeight,memo);
  22. ret += nLeft * nRight;
  23. }
  24. memo[nLow][nHeight] = ret;
  25. return ret;
  26. }

 九、不同的二叉搜索树 II

题目:给你一个整数 n ,请你生成并返回所有由 n 个节点组成且节点值从 1 到 n 互不相同的不同 二叉搜索树 。可以按 任意顺序 返回答案。

示例 1:


输入:n = 3
输出:[[1,null,2,null,3],[1,null,3,2],[2,1,3],[3,1,null,null,2],[3,2,null,1]]
示例 2:

输入:n = 1
输出:[[1]]

分析:

  • 根据例题8的解析,可知道BST总数
  • 只是需要保存一下每个节点信息

示例代码:

  1. vector<TreeNode*> generateTrees(int n) {
  2. return help(1,n);
  3. }
  4. vector<TreeNode *> help(int nLow, int nHeight)
  5. {
  6. vector<TreeNode *> ret;
  7. if (nLow > nHeight)
  8. {
  9. ret.push_back(nullptr);
  10. return ret;
  11. }
  12. for (int i = nLow; i <= nHeight; i++)
  13. {
  14. vector<TreeNode *> left = help(nLow, i - 1);
  15. vector<TreeNode *> right = help(i + 1, nHeight);
  16. for (auto & leftNode : left)
  17. {
  18. for (auto &rightNode : right)
  19. {
  20. TreeNode *root = new TreeNode(i);
  21. root->left = leftNode;
  22. root->right = rightNode;
  23. ret.push_back(root);
  24. }
  25. }
  26. }
  27. return ret;
  28. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/572356
推荐阅读
相关标签
  

闽ICP备14008679号