654. 最大二叉树
要求: 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建:
- 创建一个根节点,其值为
nums中的最大值。 - 递归地在最大值 左边 的 子数组前缀上 构建左子树。
- 递归地在最大值 右边 的 子数组后缀上 构建右子树。
返回 nums 构建的 最大二叉树 。
思路
构造树一般采用前序遍历,先构造中间节点,然后递归构造左子树和右子树。
- 确定递归函数的参数和返回值 参数是存放元素的数组,返回该数组构造的二叉树的头节点。
- 确定终止条件 当递归遍历时,如果传入的数组大小为1,则说明遍历到了叶子节点,此时应该返回一个新的节点,节点的值为nums[0]
- 确定单层遍历逻辑
首先要找到数组中最大值和其对应的下标,最大值构建根节点,下标用来切割数组。
最大值的下标的左区间,构造左子树,这里需要判断
maxIndex > 0, 因为传入数组至少有一个值; 最大值的下标的右区间,构造右子树,这里需要判断maxIndex < nums.length -1, 因为传入数组至少有一个值;
var constructMaximumBinaryTree = function(nums) {
if(nums.length == 1){
return new TreeNode(nums[0])
}
let maxValue = 0
let maxIndex = 0
for(let i=0; i<nums.length; i++){
if(nums[i]>maxValue){
maxValue = nums[i]
maxIndex = i
}
}
let node = new TreeNode(maxValue)
//每次递归调用时都构造了一个新数组,这是比较耗时的
if(maxIndex > 0){
node.left = constructMaximumBinaryTree(nums.slice(0, maxIndex))
}
if(maxIndex<nums.length-1){
node.right = constructMaximumBinaryTree(nums.slice(maxIndex+1))
}
return node
};
优化
var constructMaximumBinaryTree = function(nums) {
function traversal(arr, left, right){
if(left>right){
return null
}
let maxValue = 0
let maxIndex = 0
for(let i=left; i<=right; i++){
if(arr[i]>=maxValue){
maxValue = arr[i]
maxIndex = i
}
}
console.log(maxValue, maxIndex)
let root = new TreeNode(maxValue)
root.left = traversal(arr, left, maxIndex-1)
root.right = traversal(arr, maxIndex+1, right)
return root
}
return traversal(nums, 0, nums.length-1)
};
617. 合并二叉树
要求:给你两棵二叉树: root1 和 root2 。
想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。
返回合并后的二叉树。
注意: 合并过程必须从两个树的根节点开始。
思路
本题难点主要是如何同时遍历两个二叉树,其实就是跟遍历一个二叉树类似,只不过是传入两个节点
递归法:采用哪种遍历都是可以的,这里我使用前序遍历
var mergeTrees = function(root1, root2) {
//同时处理两个二叉树,采用前序遍历,可以直接在tree1上改也可以新建一个二叉树
//递归
if(root1 == null) return root2
if(root2 == null) return root1
root1.val += root2.val
root1.left = mergeTrees(root1.left, root2.left)
root1.right = mergeTrees(root1.right, root2.right)
return root1
};
700. 二叉搜索树中的搜索
要求:给你两棵二叉树: root1 和 root2 。
想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。
返回合并后的二叉树。
注意: 合并过程必须从两个树的根节点开始。
思路
1.递归法
var searchBST = function(root, val) {
//利用搜索树的特性,左节点比根节点小,右节点比根节点大
if(root == null || root.val == val) return root
//因为函数有返回值 所以需要去接收 或者直接返回
if(root.val > val) return searchBST(root.left, val)
if(root.val < val) return searchBST(root.right, val)
return null
};
2.迭代法 一般二叉树的迭代法,用栈模拟深度遍历,用队列模拟广度遍历,搜索二叉树中不需要搜索其他点,中间节点 > val,则往左搜索,< val 则往右搜索。
var searchBST = function(root, val) {
while(root != null){
if(root.val > val) root = root.left
else if(root.val < val) root = root.right
else return root
}
return null
};
98. 验证二叉搜索树
要求:给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
- 节点的左子树只包含 小于 当前节点的数。
- 节点的右子树只包含 大于 当前节点的数。
- 所有左子树和右子树自身必须也是二叉搜索树。
思路
本题不能直接比较左节点小于中间节点,右节点大于中间节点,因为可能会出现这样的情况,
我们需要的是左子树的所有节点小于中间节点,右子树所有节点大于中间节点。 1.递归
var isValidBST = function(root) {
let maxVal = -Infinity //记录遍历的前一个节点值
function isValid(root){
//中序遍历
if(root == null) return true
let left = isValid(root.left)
if(maxVal < root.val) {
maxVal = root.val
}else {
return false
}
let right = isValid(root.right)
return left && right
}
return isValid(root)
};
var isValidBST = function(root) {
let pre = null //记录前一个节点
function isValid(root){
//中序遍历
if(root == null) return true
let left = isValid(root.left)
if(pre != null && pre.val >= root.val) {
return false
}
pre = root
let right = isValid(root.right)
return left && right
}
return isValid(root)
};
2.迭代
var isValidBST = function(root) {
let stack = []
let cur = root
let pre = null
while(cur != null || stack.length != 0){
if(cur != null){
stack.push(cur)
cur = cur.left
}else {
cur = stack.pop()
if(pre != null && pre.val >= cur.val){
return false
}
pre = cur
cur = cur.right
}
}
return true
};