文章目录
98. 验证二叉搜索树
- 两种方法,一种是将树中序遍历转换为数组,比较是否递增
var isValidBST = function(root) {
let arr = [];
const inorder = (node) => {
if (!node) return;
node.left && inorder(node.left);
arr.push(node.val);
node.right && inorder(node.right);
}
inorder(root);
for (let i = 1; i < arr.length; i++) {
// 注意这里的等号,会有特例[2,2,2]
if (arr[i - 1] >= arr[i]) {
return false;
}
}
return true;
};
- 第二种方法迭代,同样是比较升序,利用中序遍历将中间节点和前一个节点值进行比较
var isValidBST = function(root) {
let pre = null;
const inOrder = (root) => {
if (!root) 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);
};
530. 二叉搜索树的最小绝对差
- 和上题相似
var getMinimumDifference = function(root) {
let arr = [], res = Number.MAX_VALUE;
const inOrder = (node) => {
if (!node) return;
node.left && inOrder(node.left);
arr.push(node.val);
node.right && inOrder(node.right);
}
inOrder(root);
for (let i = arr.length - 1; i > 0; i--) {
let diff = arr[i] - arr[i - 1]
res = res > diff ? diff : res;
}
return res;
};
var getMinimumDifference = function(root) {
let pre = TreeNode(), res = Number.MAX_VALUE;
const inOrder = (node) => {
if (!node) return;
node.left && inOrder(node.left);
if (pre) {
res = Math.min(res, node.val - pre.val);
}
pre = node;
node.right && inOrder(node.right);
}
inOrder(root);
return res;
};
501. 二叉搜索树中的众数
- 最初是想将树转为数组然后判断众数的,代码非常的臃肿
- 接下来介绍正确方法
- 用额外空间map
var findMode = function(root) {
let map = new Map();
const inOrder = (node) => {
if (!node) return;
node.left && inOrder(node.left);
map.set(node.val, map.has(node.val) ? map.get(node.val) + 1 : 1);
node.right && inOrder(node.right);
}
inOrder(root);
let res = [], cnt = map.get(root.val);
map.forEach((value, key) => {
if (cnt === value) {
res.push(key);
} else if (cnt < value) {
cnt = value;
res.length = 0;
res.push(key);
}
})
return res;
};
- 顺便介绍一下js中数组的清空
let a = [1, 2, 3];
a.length = 0;
// 赋予数组的长度length小于本身的长度,数组中后面的元素将被截断;赋予数组的长度length大于本身的长度,将扩展数组长度,多的元素为undefined。效率最高
a.splice(0);
// splice清空,效率居中
a= [];
// 直接置空,效率最低
- 还有一种不需要map的,利用pre存储前一个节点来操作(暂时使用不是很熟练)
var findMode = function(root) {
let res = [], pre = root, cnt = 0, maxCnt = 1;
const inOrder = (node) => {
if (!node) return;
node.left && inOrder(node.left);
if (pre.val === node.val) {
cnt++;
} else {
cnt = 1;
}
pre = node;
if (cnt === maxCnt) {
res.push(node.val);
} else if (cnt > maxCnt) {
maxCnt = cnt;
res.length = 0;
res.push(node.val);
}
node.right && inOrder(node.right);
}
inOrder(root);
return res;
};
236. 二叉树的最近公共祖先
- 用后续遍历从底层向上传最近的祖先
- 若一个子树中没有p或q节点,那么这棵子树的根节点会返回一个null;而如果有,从最近的公共祖先节点开始会将自己的节点通过后序遍历传递上来
var lowestCommonAncestor = function(root, p, q) {
if (!root || root === p || root === q) return root;
let left = lowestCommonAncestor(root.left, p ,q);
let right = lowestCommonAncestor(root.right, p, q);
if (left && right) return root;
else if (left && !right) return left;
else if (!left && right) return right;
else return null; // (left == NULL && right == NULL)
};
235. 二叉搜索树的最近公共祖先
- 和前一题写法稍有不同
- 在递归函数有返回值时,我们需要确定要搜索一条边还是搜索整个树
搜索一条边的写法:
if (递归函数(root->left)) return ;
if (递归函数(root->right)) return ;
搜索整个树的写法:
left = 递归函数(root->left);
right = 递归函数(root->right);
left与right的逻辑处理;
- 那么前一题就是搜索整个树,这里就是搜索一条边
var lowestCommonAncestor = function(root, p, q) {
if (!root) return root;
if (root.val > p.val && root.val > q.val) {
return lowestCommonAncestor(root.left, p, q);
}
if (root.val < p.val && root.val < q.val) {
return lowestCommonAncestor(root.right, p, q);
}
return root;
};
- 然鹅这题用迭代也十分简洁( ̄▽ ̄)/
var lowestCommonAncestor = function(root, p, q) {
// 使用迭代的方法
while(root) {
if(root.val>p.val&&root.val>q.val) {
root = root.left;
}else if(root.val<p.val&&root.val<q.val) {
root = root.right;
}else {
return root;
}
}
return null;
};
701. 二叉搜索树中的插入操作
- 根据搜索树的性质遍历到对应的空节点就行了
- 创建一个节点时前面要加new(第一次忘记了然后找不出错╥﹏╥)
var insertIntoBST = function(root, val) {
const travel = (node) => {
if (!node) {
return new TreeNode(val);
}
if (node.val < val) {
node.right = travel(node.right);
}
if (node.val > val) {
node.left = travel(node.left);
}
return node;
}
return travel(root);
};
450. 删除二叉搜索树中的节点
- 有以下五种情况:
第一种情况:没找到删除的节点,遍历到空节点直接返回了找到删除的节点
第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。
var deleteNode = function(root, key) {
if (!root) return null;
if (key > root.val) {
root.right = deleteNode(root.right, key);
return root;
} else if (key < root.val) {
root.left = deleteNode(root.left, key);
return root;
} else {
// 场景1: 该节点是叶节点
if (!root.left && !root.right) {
return null
}
// 场景2: 有一个孩子节点不存在
if (root.left && !root.right) {
return root.left;
} else if (root.right && !root.left) {
return root.right;
}
// 场景3: 左右节点都存在
const rightNode = root.right;
// 获取最小值节点
const minNode = getMinNode(rightNode);
// 将待删除节点的值替换为最小值节点值
root.val = minNode.val;
// 删除最小值节点
root.right = deleteNode(root.right, minNode.val);
return root;
}
};
function getMinNode(root) {
while (root.left) {
root = root.left;
}
return root;
}
108. 将有序数组转换为二叉搜索树
- 整体思路就是二分
var sortedArrayToBST = function(nums) {
const travel = (left, right) => {
if (left > right) return null;
let mid = left + Math.floor((right - left) / 2);
let root = new TreeNode(nums[mid]);
root.left = travel(left, mid - 1);
root.right = travel(mid + 1, right);
return root;
}
return travel(0, nums.length - 1);
};
538. 把二叉搜索树转换为累加树
- 据题意确定遍历方式:右中左,然后将节点val累加即可
var convertBST = function(root) {
let pre = 0
const travel = (cur) => {
if (!cur) return;
travel(cur.right);
cur.val += pre;
pre = cur.val;
travel(cur.left);
}
travel(root);
return root;
};