二叉搜索树
二叉搜索树定义如下:
- 空树是二叉搜索树
- 节点的左子树只包含小于当前节点的数。
- 节点的右子树只包含大于当前节点的数。
- 所有左子树和右子树自身必须也是二叉搜索树。 考察思路:特性(判定)、操作(构造)
参考:juejin.cn/book/684473…
验证二叉搜索树 【力扣98】
示例
示例1
输入: [5,4,6,null,null,3,7]
输出: false
示例2
输入: [5,3,6,2,4,null,7]
输出:true
思路
根据二叉搜索树的定义,我们只需要递归地对非空树中的左右子树进行遍历,检验每棵子树中是否都满足左子树中的结点值<根结点<右子树。
示例1中每个结点都满足左儿子结点<根结点<右儿子结点,但③小于⑤,显然不应该在⑤的右子树中,因此需要注意数据域的继承。
代码
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {boolean}
*/
var isValidBST = function(root) {
if(!root) return true;
const isValid = function(root,minVal,maxVal) {
if(!root) return true;
if(root.val>minVal && root.val<maxVal) {
return isValid(root.left,minVal,root.val)&&isValid(root.right,root.val,maxVal);
}else {
return false;
}
}
return isValid(root,-Infinity,Infinity);
};
将有序数组转换为二叉搜索树【力扣108】
将升序序列转换成高度平衡的二叉搜索树。高度平衡:每个节点的左右两个子树的高度差的绝对值不超过 1
示例
输入:[1,2,3,4,5,6,7]
输出:[4,2,6,1,3,5,7]
思路
观察示例,可以看出平衡二叉搜索树像是从序列中间把树根拎起来一样,左半边序列和右半边序列再分别从中间拎起,那么我们只需要递归的对序列进行二分即可。
代码
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {number[]} nums
* @return {TreeNode}
*/
var sortedArrayToBST = function(nums) {
const buildBST = function(low,high) {
if( low > high ) {//序列已经遍历完
return null;
}
let mid = Math.floor(low + (high - low)/2);//获取序列中间的数字
let curr=new TreeNode(nums[mid]);//中间数作为当前结点
curr.left = buildBST(low,mid-1);//用较小数列递归建立左子树
curr.right = buildBST(mid+1,high);//用较大数列递归建立右子树
return curr;
}
const root=buildBST(0,nums.length-1);
return root;
};
平衡二叉树
判定:【力扣110】
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {boolean}
*/
var isBalanced = function(root) {
let flag = true;
const dfs = function(root) {
if(!root||!flag) return 0;
let left=dfs(root.left);
let right=dfs(root.right);
if(Math.abs(left-right)>1){
flag=false;
return 0;
}
return Math.max(left,right)+1;
}
dfs(root);
return flag;
};
构造:【力扣1382】
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {TreeNode}
*/
var balanceBST = function(root) {
//中序遍历,将二叉搜索树转换为有序数组
let vals = [];
const inOrderTravel = function(root){
if(!root) return;
inOrderTravel(root.left);
vals.push(root.val);
inOrderTravel(root.right);
}
inOrderTravel(root);
// console.log(vals);
//有序数组->平衡二叉搜索树
const BST = function(low,high){
if(low>high) return null;
let mid=Math.floor(low+(high-low)/2);
let root=new TreeNode(vals[mid]);
root.left=BST(low,mid-1);
root.right=BST(mid+1,high);
return root;
}
return BST(0,vals.length-1);
};
堆
完全二叉树:
- 除了倒数第一层外,每层都是满的
- 倒数第一层所有结点都排列在这一层的最左边连续不断
- 某结点的索引值为n,则其父结点索引为(n-1)/2,子结点索引值为2n+1和2n+2
小顶堆:所有结点的值都大于父结点的值
大顶堆:所有结点的值都小于父结点的值 关键点为堆结点的插入与删除,以下题为例:数组中的第k个最大元素
/**
* @param {number[]} nums
* @param {number} k
* @return {number}
*/
var findKthLargest = function(nums, k) {
const len = nums.length;
const heap = [];
let n = 0;
//建立堆
const createHeap = function(){//初始化一个大小为k的小顶堆
for(let i=0;i<k;i++){
insert(nums[i]);
}
}
const insert = function(num){//堆的插入操作
heap[n]=num;
upHeap(0,n);
n++;
}
const upHeap = function(low,high){//自底向上调整,维持小顶堆
let i = high;
let j = Math.floor((i-1)/2);//父结点
while(j>=low){
if(heap[i] < heap[j]){
let temp = heap[i];
heap[i] = heap[j];
heap[j] = temp;
}
i = j;//当前结点更新为父结点
j = Math.floor((j-1)/2);//父结点更新为祖父结点
}
}
//更新堆
const updateHeap = function(){//数组中剩余元素用来更新小顶堆
for(let i=k;i<len;i++){
if(nums[i]>heap[0]){
heap[0]=nums[i];
downHeap(0,n)
}
}
}
const downHeap = function(low,high){//自顶向下调整
let i = low;
let j = i*2+1;//子结点
while(j<=high){
if(j+1<=high && heap[j]>heap[j+1]) j = j+1;//与儿子里小的那个交换
if(heap[i]>heap[j]){
let temp = heap[i];
heap[i] = heap[j];
heap[j] = temp;
}
i = j;
j = j*2+1;
}
}
createHeap();
updateHeap();
return heap[0];//堆顶元素为最大的K个数中的最小数,即第k大的元素
};