力扣关于树的题目(二)(二叉搜索树)

二叉搜索树的问题

1. 二叉搜索树的属性

二叉搜索树的属性是一个节点的值大于左节点的值,小于右节点的值

1. 700. 二叉搜索树中的搜索

相当于二分搜索,根节点比较,如果小往右走,大往左走

/**
 * @param {TreeNode} root
 * @param {number} val
 * @return {TreeNode}
 */
var searchBST = function(root, val) {
    let res = null;
    const getChildTree = (root) => {
        if(!root) {
            return;
        }
        res.push(root.val);
        getChildTree(root.left);
        getChildTree(root.right);
    }
    const backtrace = (root) => {
        if(!root) {
            return null;
        }
        if(root.val === val) {
            res = root;
            return;
        }else if(root.val > val) {
            backtrace(root.left)
        }else if(root.val < val) {
            backtrace(root.right)
        }
    }
    backtrace(root)
    return res;
};
2. 98. 验证二叉搜索树

中序遍历,比较大小

/**
 * @param {TreeNode} root
 * @return {boolean}
 */
let pre = null;
var isValidBST = function (root) {
    let pre = null;
    const inOrder = (root) => {
        if (root === null)
            return true;
        let left = inOrder(root.left);

        if (pre !== null && pre.val >= root.val)
            return false;
        pre = root;

        let right = inOrder(root.right);
        return left && right;
    }
    return inOrder(root);
};

3. 530. 二叉搜索树的最小绝对差

要找最小绝对差,相邻的两个节点的一定的最小的,只需要比较相邻的节点的差值哪个更小

/**
 * @param {TreeNode} root
 * @return {number}
 */
var getMinimumDifference = function(root) {
    let pre = -1;
    let min = Infinity;
    const backtrace = (root) => {
      if (!root) {
          return;
      }
      backtrace(root.left);
      if (pre === -1) {
        pre = root.val;
      }else {
          min = Math.min(min,root.val - pre);
          pre = root.val;
      }
      backtrace(root.right);
    }
    backtrace(root)
    return min;
};
  1. 501. 二叉搜索树中的众数

    又是中序遍历,数值一样的数,在中序遍历的时候一定是挨在一起的

    /**
     * @param {TreeNode} root
     * @return {number[]}
     */
    var findMode = function(root) {
        let maxCount = 1;
        let resNum = [];
        let currentCount = 1;
        let pre;
        const inorder = (root) => {
            if(!root) {
                return;
            }
            inorder(root.left);
            if(pre === undefined) {
                pre = root.val;
            }else if (pre === root.val) {
                currentCount++;
            }else {
                if(maxCount < currentCount){
                    maxCount = currentCount;
                    resNum = [];
                    resNum.push(pre);
                }else if(maxCount === currentCount) {
                    resNum.push(pre)
                }
                pre = root.val;
                currentCount = 1;
            }
            inorder(root.right)
        }
        inorder(root);
        if (currentCount > maxCount) {
            resNum = [];
            resNum.push(pre);
        }else if(currentCount == maxCount) {
            resNum.push(pre);
        }
        return resNum;
    };
    
5. 538. 把二叉搜索树转换为累加树

这题是反中序遍历,右头左,将右边的数累加再赋新的值给树

/**
 * @param {TreeNode} root
 * @return {TreeNode}
 */
var convertBST = function(root) {
    let sum = 0;
    const bianli = (root) => {
        if (!root) {
            return;
        }
        bianli(root.right)
        sum += root.val;
        root.val = sum;
        bianli(root.left)
    }
    bianli(root)
    return root;
};
6. 235. 二叉搜索树的最近公共祖先

实际上是路径问题,判断走左边还是走右边

/**
 * @param {TreeNode} root
 * @param {TreeNode} p
 * @param {TreeNode} q
 * @return {TreeNode}
 */
var lowestCommonAncestor = function(root, p, q) {
    let res;
    // make p is smaller
    if(p.val > q.val) {
        let tmp = p;
        p = q;
        q = tmp;
    }
    const order = (root) => {
        if(!root) {
            return null;
        }
        if((p.val < root.val && root.val < q.val) || root.val === q.val || root.val === p.val) {
            res = root
            return
        }else if(root.val > q.val) {
            order(root.left)
        }else {
            order(root.right)
        }
    }
    order(root)
    return res;
};

2. 二叉搜索树的修改和构造

1. 701. 二叉搜索树中的插入操作

经过每一个节点,判断下一个走左边还是右边,如果找到空的就插入

/**
 * @param {TreeNode} root
 * @param {number} val
 * @return {TreeNode}
 */
var insertIntoBST = function(root, val) {
    if (!root) {
        return root = new TreeNode(val);
    }
    const inOrder = (root) => {
      if (root.val < val) {
          if (root.right) {
              inOrder(root.right);
          }else {
              root.right = new TreeNode(val)
              return;
          }
      }
        if (root.val > val) {
            if (root.left) {
                inOrder(root.left);
            }else {
                root.left = new TreeNode(val)
                return;
            }
        }
    }
    inOrder(root);
    return root;
};
2. 450. 删除二叉搜索树中的节点

这里有两个问题,第一个是找到节点删除,删除之后构造新的二叉搜索树

构建新的二叉树的方法:找到节点,然后更改子树的结构:根节点变成root.right,找到root.right的最左子节点,然后在节点的左边镶上root.left

/**
 * @param {TreeNode} root
 * @param {number} key
 * @return {TreeNode}
 */
var deleteNode = function(root, key) {
    const inOrder = (root) => {
      if (!root) {
          return root;
      }
      // delete the node
      if (root.val === key) {
          if (!root.left) {
              return root.right;
          }
          else if (!root.right) {
              return root.left;
          }else {
              let cur = root.right;
              while (cur.left) {
                  cur = cur.left;
              }

              cur.left = root.left;
              root = root.right;
              return root;
          }
      }
      if (root.val > key) {
          root.left = inOrder(root.left);
      }
      if (root.val < key) {
          root.right = inOrder(root.right)
      }
      return root;
    }
    return inOrder(root)
};
3. 669. 修剪二叉搜索树

root根据val分成三种情况:

  1. 比low还小,更改root成右边的节点

  2. 比high还大,更改root成左边的节点

  3. 在范围内,返回root,但是重新定义他的左子树和右子树

/**
 * @param {TreeNode} root
 * @param {number} low
 * @param {number} high
 * @return {TreeNode}
 */
var trimBST = function(root, low, high) {
    const bianli = (root,low,high) => {
      if (!root) {
          return null;
      }
      let node;
      if (root.val < low) {
          node = bianli(root.right,low,high)
      }else if (root.val > high) {
          node = bianli(root.left,low,high)
      }else {
          node = root;
          node.left = bianli(root.left,low,high);
          node.right = bianli(root.right,low,high)
      }
      return node;
    }
    return bianli(root,low,high)
};
4. 108. 将有序数组转换为二叉搜索树

跟二分查找有点相似,找到中间的节点,构造节点,再确定左子树,右子树

/**
 * @param {number[]} nums
 * @return {TreeNode}
 */
var sortedArrayToBST = function(nums) {
    const makeTree = (start,end) => {
      if (end < start) {
          return null;
      }

      // let len = end - start + 1;
      let mid = Math.floor(start + (end - start) / 2);
      let root = new TreeNode(nums[mid]);
      root.left = makeTree(start,mid-1);
      root.right = makeTree(mid+1,end);
      return root;
    }
    return makeTree(0,nums.length-1);
};

总结

  1. 二叉搜索树的属性问题一般是遍历和找路径两类,遍历首先考虑中序遍历,找路径就是判断下一步往左走还是往右走
  2. 构造(修改)二叉搜索树的一般思路:确定根节点,递归构造(修改)左子树和右子树
posted @ 2022-04-21 16:25  kihyun  阅读(18)  评论(0编辑  收藏  举报