来自百度百科的解释:二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。二叉搜索树作为一种经典的数据结构,它既有链表的快速插入与删除操作的特点,又有数组快速查找的优势;所以应用十分广泛,例如在文件系统和数据库系统一般会采用这种数据结构进行高效率的排序与检索操作。
由于若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值这个特点,使用中序遍历二叉搜索树时,遍历得到的序列是升序的。利用这个特点,可以解决以下两道问题。在此之前,先给出树的定义。
class TreeNode{
int val;
TreeNode left;
TreeNode right;
public TreeNode(){};
public TreeNode(int val){
this.val = val;
}
public TreeNode(int val, TreeNode left, TreeNode right){
this.val = val;
this.left = left;
this.right = right;
}
}
验证二叉搜索树
给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。有效二叉搜索树定义如下:
- 节点的左子树只包含 小于 当前节点的数。
- 节点的右子树只包含 大于 当前节点的数。
- 所有左子树和右子树自身必须也是二叉搜索树。
示例1:
注:图片转载自leetcode官网
输入:root = [5,1,4,null,null,3,6]
输出:false
解释:根节点的值是 5 ,但是右子节点的值是 4 。
class Solution {
TreeNode pre = null;
boolean isValid = true;
public boolean isValidBST(TreeNode root) {
tarversal(root);
return isValid;
}
private void tarversal(TreeNode root){
if(root == null) return;
tarversal(root.left);
if(pre != null){
if(pre.val >= root.val){
isValid = false;
return;
}
}
pre = root;
tarversal(root.right);
}
}
这题的解题思路先定义isValid,初始为true。定义一个pre变量用于保存当前结点的前一个结点,在遍历的过程中比较前一个结点的值是否小于当前结点的值,由于采用中序遍历,如果是二叉搜素树,前一个结点的值必然小于当前结点值,因此如果大于,将isValid的值设为false,同时结束遍历。如果遍历的过程中,所有结点的值都小于前一个结点的值,遍历结束,isValid为初始值true。
这里详细说明上述代码的整个执行流程。进入tarversal方法。首先遍历根结点5,递归进入5的left结点1,之后继续递归进入结点1的left。结点1的left为空,递归返回。由于pre为null,不进入if判断。将结点1赋值给pre。递归进入结点1的right,结点1的right为空,递归返回,结点1递归返回。根节点5的left遍历完成。pre不为空,进入if判断,pre的值1小于当前结点的值5。之后将结点5赋值给pre。进入根结点5的right。
根节点5的right为4,继续进入结点4的left,继续进入结点3的left。此时结点3的left为空,递归返回。pre的值为5大于当前结点的值3,isValid设置为false,递归返回。此时结点4的left遍历结束,进入if判断,pre的值为5大于当前结点的值4,isValid再次设置为false,递归返回。根结点5的right遍历完成。tarversal的方法完成。最后返回在isValidBST方法返回isValid。
二叉搜索树中第K小的元素
给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 1 开始计数)。
示例1:
注图片转载自leetcode官网
输入:root = [5,3,6,2,4,null,null,1], k = 3
输出:3
class Solution {
int ans = -1;
int kth = 0;
public int kthSmallest(TreeNode root, int k) {
tarversal(root, k);
return ans;
}
private void tarversal(TreeNode root, int k){
if(root == null) return;
tarversal(root.left, k);
kth++;
if(kth == k){
ans = root.val;
return;
}
tarversal(root.right, k);
}
}
这题的解题思路是先定义一个变量kth,用于记录遍历到第几个结点,如果kth等于k,表示遍历到第k个结点,由于遍历时得到的序列是升序的,因此得到的第k个结点就是第k小的。
这里详细描述上述代码的执行流程。进入tarversal方法,首先遍历根结点5,进入根结点的left,进入结点3的left,进入结点2的left,进入结点1的left。结点1的left为空,递归返回。kth++,kth不等于k(3),进入结点1的right。结点1的right为空,递归返回。到结点2,kth++,kth不等于k(3),进入结点2的right。结点2的right为空,递归返回。到结点3,kth++,kth等于3,将结点3的值赋值给ans,返回。到根结点5,kth++,kth不等于3,进入根结点的right,进入结点6的left,为空返回,kth++,kth不等于3,进入结点6的right,为空,返回。根结点的right遍历结束,tarversal遍历完成。kthSmallest返回ans。