var mergeTrees = function (root1, root2) {
const preOrder = (root1, root2) => {
if(!root1)
return root2
if(!root2)
return root1;
root1.val += root2.val;
root1.left = preOrder(root1.left, root2.left);
root1.right = preOrder(root1.right, root2.right);
return root1;
}
return preOrder(root1, root2);
};
递归
var searchBST = function(root, val) {
if(!root) return null;
if(root.val > val) {
return searchBST(root.left, val);
}else if(root.val < val) {
return searchBST(root.right, val);
}else{
return root;
}
};
迭代
var searchBST = function(root, val) {
while(root) {
if(root.val < val) {
root = root.right;
}else if(root.val > val) {
root = root.left;
}else{
return root;
}
}
return null;
};
思路:二叉搜索树的一个特性:二叉搜索树的中序遍历是有序的。
误区:递归判断根节点的值大于左节点并小于右节点的值,忽略了左子树的全部节点都要小于根节点,并且右子树的全部节点都要大于根节点。
错误代码示范
// 比如 [5,4,6,null,null,3,7] 该代码就判断错误了
var isValidBST = function(root) {
if(!root) return true;
if(root.left && root.left.val >= root.val) return false;
if(root.right && root.right.val <= root.val) return false;
return isValidBST(root.left) && isValidBST(root.right);
};
最直观的方式是把二叉树转变为数组来判断,但其实也不用转变成数组,可以在递归遍历的过程中直接判断是否有序。
借助数组实现
var isValidBST = function(root) {
const arr = [];
const dfs = (root) => {
if(!root) return true;
dfs(root.left);
arr.push(root.val);
dfs(root.right);
}
dfs(root);
for(let i = 1; i < arr.length; i++) {
if(arr[i] <= arr[i - 1]) return false;
}
return true;
};
递归
思路:与双指针的思路很像,初始化一个空指针pre
,pre
存放遍历的前一个值,将其与当前值root
进行比较。
var isValidBST = function(root) {
let pre = null;
const dfs = (root) => {
if(!root) return true;
// 注意:要用变量存放遍历左子树与右子树的结果,利用这两个遍历的值做递归的返回值
let left = dfs(root.left);
if(pre && pre.val >= root.val) return false;
pre = root;
let right = dfs(root.right);
return left && right;
}
return dfs(root);
};
借助数组
var getMinimumDifference = function(root) {
// 最小差值不一定是相邻节点
let minDiff = Infinity;
// 借助数组
const arr = [];
const dfs = (root) => {
if(root) {
dfs(root.left);
arr.push(root.val);
dfs(root.right);
}
}
dfs(root);
for(let i = 1; i < arr.length; i++) {
let diff = Math.abs(arr[i] - arr[i - 1]);
minDiff = Math.min(diff, minDiff);
}
return minDiff;
};
双指针(递归)
思路:用一个pre节点记录一下root节点 即当前节点的前一个节点。在递归过程中更新最小值。
var getMinimumDifference = function(root) {
// 最小差值不一定是相邻节点
let pre = null;
let minDiff = Infinity;
const dfs = (root) => {
if(!root) return;
// 注意: 这里不需要用变量去接遍历左子树与右子树的值, 因为我们遍历左子树与右子树的目的是更新minDiff的值,在遍历过程中 自然更新了minDiff它的值 最后把minDiff返回就行了
dfs(root.left);
if(pre && minDiff > Math.abs(root.val - pre.val)) minDiff = Math.abs(root.val - pre.val);
pre = root;
dfs(root.right);
return minDiff;
}
return dfs(root);
};
⭐迭代法-中序遍历
感觉很绕,自己比较难想出来/难做出来,但理解了之后,觉得思路跟递归很像,只是迭代法用的是while
循环。
var getMinimumDifference = function(root) {
let stack = []
let cur = root
let res = Infinity
let pre = null
while(cur || stack.length) {
if(cur) {
stack.push(cur)
cur = cur.left
} else {
cur = stack.pop()
if(pre) res = Math.min(res, cur.val - pre.val)
pre = cur
cur = cur.right
}
}
return res
}
普通二叉树解法
思路:遍历整棵二叉树,用map
统计频率,把频率排个序(先把map转成数组再排序),最后取前面高频的元素的集合。
var findMode = function(root) {
const map = new Map();
const dfs = (root) => {
if(!root) return;
dfs(root.left);
map.set(root.val, map.has(root.val) ? map.get(root.val) + 1 : 1);
dfs(root.right);
}
dfs(root);
let arr = Array.from(map), ans = [];
arr.sort((a,b) => b[1] - a[1]);
for(let i = 1; i < arr.length; i++) {
if(arr[i][1] === arr[i - 1][1]) {
ans.push(arr[i][0]);
}else{
break;
}
}
ans.push(arr[0][0]);
return ans;
};
利用二叉搜索树性质
思路:双指针,一遍遍历二叉搜索树,遍历的同时记录最大频数并更新结果集。
var findMode = function(root) {
let pre = null, result = [], maxCount = 0, count = 0;
const dfs = (root) => {
if(!root) return;
dfs(root.left);
if(!pre) {
count = 1;
}else if(pre.val === root.val) {
count++;
}else {
count = 1;
}
if(count === maxCount) result.push(root.val);
if(count > maxCount) {
maxCount = count;
// 出现更大的次数时 清空之前的结果集
result = [];
result.push(root.val);
}
pre = root;
dfs(root.right);
}
dfs(root);
return result;
};