513.找树左下角的值
思路:
这道题可使用递归或者迭代方法来做 迭代更简单一点 ,到达叶子节点,也就是 left 和 right 都为 null 的时候,判断一下现在所在深度是不是大于最深的深度,如果是,更新一下答案值。最终更新结果就是最左边且深度最大的节点的值。尽管也会遍历右子树,但是深度不比左子树的深,也不会更新,也就是同样在最底层的左子树会优先赋值给 resNode。
代码实现
var findBottomLeftValue = function (root) {
let maxDepth = 0;
let result = null;
const traversal = function (root, depth) {
if (root.left === null && root.right === null) {
//当遇到叶子节点的时候,就需要统计一下最大的深度了,所以需要遇到叶子节点来更新最大深度。
if (depth > maxDepth) {
maxDepth = depth
result = root.val
}
return
}
root.left && traversal(root.left, depth + 1)
root.right && traversal(root.right, depth + 1)
return
}
traversal(root, 1);
return result
};
//层序遍历
var findBottomLeftValue = function (root) {
let queue = []
if (root === null) {
return null
}
queue.push(root);
let resNode;
while (queue.length) {
let length = queue.length;
for (let i = 0; i < length; i++) {
let node = queue.shift()
//记录最后一行的第一个节点的数值
if (i === 0) {
resNode = node.val
}
node.left && queue.push(node.left);
node.right && queue.push(node.right);
}
}
return resNode
};
112. 路径总和 113.路径总和ii
思路
这道题 求单条路径用递归需要返回值 而求所有路径 则不需要
代码实现:
路径总和
var hasPathSum = function (root, targetSum) {
const traversal = function (root, count) {
if (!root.left && !root.right && count === 0) { return true }
if (!root.left && !root.right && count !== 0) { return false }
if (root.left) {
if (traversal(root.left, count - root.left.val)) {
return true
}
}
if (root.right) {
if (traversal(root.right, count - root.right.val)) {
return true
}
}
return false
}
if (!root) {
return false
}
return traversal(root, targetSum - root.val)
};
//迭代
var hasPathSum = function (root, targetSum) {
if (!root) {
return false
}
let nodeArr = [root];
let valArr = [0]
while (nodeArr.length) {
let node = nodeArr.shift()
let val = valArr.shift()
val += node.val
if (node.left === null && node.right === null && val === targetSum) {
return true
}
if (node.left) {
nodeArr.push(node.left)
valArr.push(val)
}
if (node.right) {
nodeArr.push(node.right)
valArr.push(val)
}
}
return false
};
路径总和ii:
var pathSum = function (root, targetSum) {
// 递归法
// 要遍历整个树找到所有路径,所以递归函数不需要返回值, 与112不同
const res = [];
const traversal = (node, sum, path) => {
// 遇到了叶子节点且找到了和为sum的路径
if (sum === 0 && !node.left && !node.right) {
res.push([...path])//深拷贝
return;
}
if (!node.left && !node.right) {
return;
}
if (node.left) {
path.push(node.left.val);
traversal(node.left, sum - node.left.val, path)
path.pop()// 回溯
}
if (node.right) {
path.push(node.right.val);
traversal(node.right, sum - node.right.val, path)
path.pop()// 回溯
}
return
}
if (!root) {
return res
}
traversal(root, targetSum - root.val, [root.val])
return res
};
//递归精简版
var pathSum = function (root, targetSum) {
// 递归法
// 要遍历整个树找到所有路径,所以递归函数不需要返回值, 与112不同
const res = [], pathArr = [];
const traversal = (node, sum) => {
// 遇到了叶子节点且找到了和为sum的路径
pathArr.push(node.val)
sum -= node.val
if (sum === 0 && !node.left && !node.right) {
res.push([...pathArr])//深拷贝
}
node.left && traversal(node.left, sum)
node.right && traversal(node.right, sum)
let cur = pathArr.pop()
//总数需要减去当前节点的值 然后进行下一次递归
sum -= cur
}
if (!root) {
return res
}
traversal(root, targetSum)
return res
};
//迭代
var pathSum = function (root, targetSum) {
if (!root) {
return []
}
let nodeArr = [root];
let resArr = [];// 记录符合目标和的返回路径
let tempArr = [[]];// 对应路径
let countArr = [0];//对应和
while (nodeArr.length) {
let curNode = nodeArr.shift()
let curVal = countArr.shift();
let curNodeArr = tempArr.shift()
curVal += curNode.val;
curNodeArr.push(curNode.val)
// 为叶子结点,且和等于目标数,将此次结果数组push进返回数组中
if (curNode.left === null && curNode.right === null && curVal === targetSum) {
resArr.push(curNodeArr)
}
if (curNode.left) {
nodeArr.push(curNode.left);
countArr.push(curVal);
tempArr.push([...curNodeArr])
}
if (curNode.right) {
nodeArr.push(curNode.right);
countArr.push(curVal);
tempArr.push([...curNodeArr])
}
}
return resArr
}
106.从中序与后序遍历序列构造二叉树 105.从前序与中序遍历序列构造二叉树
中后序:
-
第一步:如果数组大小为零的话,说明是空节点了。
-
第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
-
第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
-
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
-
第五步:切割后序数组,切成后序左数组和后序右数组
-
第六步:递归处理左区间和右区间
前中序是一样的道理
代码实现:
106.从中序与后序遍历序列构造二叉树
function TreeNode (val, left, right) {
this.val = (val === undefined) ? 0 : val
this.left = (left === undefined) ? null : left
this.right = (right === undefined) ? null : right
}
var buildTree = function (inorder, postorder) {
if (!inorder.length) {
return null
}
//取出栈顶元素 也就是后序数组中的 根元素
const rootVal = postorder.pop()
let rootIndex = inorder.indexOf(rootVal)// 获取中间节点在中序遍历中的下标
const root = new TreeNode(rootVal)
root.left = buildTree(inorder.slice(0, rootIndex), postorder.slice(0, rootIndex))
root.right = buildTree(inorder.slice(rootIndex + 1), postorder.slice(rootIndex))
return root
};
105.从前序与中序遍历序列构造二叉树
function TreeNode (val, left, right) {
this.val = (val === undefined) ? 0 : val
this.left = (left === undefined) ? null : left
this.right = (right === undefined) ? null : right
}
var buildTree = function (preorder, inorder) {
if (!inorder.length) {
return null
}
//取出栈顶元素 也就是后序数组中的 根元素
const rootVal = preorder.shift()
let rootIndex = inorder.indexOf(rootVal)// 获取中间节点在中序遍历中的下标
const root = new TreeNode(rootVal)
//关于为何从0开始 是因为前序数组的第一个元素已经被取出来了所以从0开始
root.left = buildTree(preorder.slice(0, rootIndex), inorder.slice(0, rootIndex))
root.right = buildTree(preorder.slice(rootIndex), inorder.slice(rootIndex + 1))
return root
};
总结
今天总体偏难 需要注意 前后序是无法进行构造二叉树 因为前序后序虽然可以判别出根元素 但是无法切割左右部分,所以无法构造