102. Binary Tree Level Order Traversal
function TreeNode(val) {
this.val = val;
this.left = this.right = null;
}
这个题比较符合人们考虑方式的做法是用BFS一层层来遍历二叉树。
BFS是从根节点出发,一层一层的扩散出去,每次都取当前层的儿子节点,一直遍历下去。
一开始我写成这样:
// 执行用时 : 76 ms , 在所有 JavaScript 提交中击败了 23.67% 的用户
// 内存消耗 : 34.9 MB , 在所有 JavaScript 提交中击败了 21.39% 的用户
/**
* @param {TreeNode} root
* @return {number[][]}
*/
var levelOrder = function(root) {
let res = []
let level = []
level.push(root)
let children = function (parents) {
let c = []
for (let i = 0; i < parents.length; i++) {
if (parents[i] !== undefined && parents[i] !== null) {
c.push(parents[i].left)
c.push(parents[i].right)
}
}
return c
}
while (level.length > 0) {
let vals = []
for (let i = 0; i < level.length; i++) {
if (level[i]) {
vals.push(level[i].val)
}
}
if (vals.length > 0) {
res.push(vals)
}
level = children(level)
}
return res
};
通过是通过了,真是这个用时让我有点困惑,这还能怎么快?然后我想到了之前把for ... of ...改成for (let i = 0 .....) 这种形式居然提高了速度,于是我试着把里面的push换成了索引的方式来存值,类似这样:
let children = function (parents) {
let c = []
let j = 0
for (let i = 0; i < parents.length; i++) {
if (parents[i] !== undefined && parents[i] !== null) {
c[j++] = parents[i].left
c[j++] = parents[i].right
}
}
return c
}
结果 …… 真的变快了。😂
执行用时 :64 ms, 在所有 JavaScript 提交中击败了85.56%的用户
内存消耗 :36.1 MB, 在所有 JavaScript 提交中击败了5.47%的
最后我把所有的push都改了后:
执行用时 :60 ms, 在所有 JavaScript 提交中击败了94.25%的用户
内存消耗 :35.9 MB, 在所有 JavaScript 提交中击败了5.47%的用户炫耀一下:
最终代码:
/**
* @param {TreeNode} root
* @return {number[][]}
*/
var levelOrder = function(root) {
let children = function (parents) {
let c = []
let j = 0
for (let i = 0; i < parents.length; i++) {
if (parents[i] !== undefined && parents[i] !== null) {
c[j++] = parents[i].left
c[j++] = parents[i].right
}
}
return c
}
let getVals = function (level) {
let vals = []
let j = 0
for (let i = 0; i < level.length; i++) {
if (level[i]) {
vals[j++] = level[i].val
}
}
return vals
}
let res = []
let level = []
level[0] = root
let j = 0
while (level.length > 0) {
let vals = getVals(level)
if (vals.length > 0) {
res[j++] = vals
}
level = children(level)
}
return res
};
这个题也可以用DFS来做, 这样递归写起来很简洁,看着也比较舒服,复杂度O(N)
DFS的做法是一直在一条分支上走到底,然后再往上回溯
// 64 ms 85.56%
var levelOrder = function(root) {
if (!root) return []
let res = []
let level = 0
let DFS = function (parent, level) {
if (!parent) return
if (res.length < level + 1) {
res.push([])
}
res[level].push(parent.val)
DFS (parent.left, level + 1)
DFS (parent.right, level + 1)
}
DFS (root, level)
return res
};
102 二叉树的最大深度
DFS和BFS都可以做。用BFS的话,因为是一层层的从上往下扫荡,一直扫描到最底层即可。用DFS的话,用递归写起来很简洁。
// 72 ms 74.29%
// 37.3 mb 36.36%
var maxDepth = function (root) {
if (!root) return 0;
return 1 + Math.max(maxDepth(root.left), maxDepth(root.right))
};
111 二叉树的最小深度
同样BFS和DFS都可以做。同样用DFS写起来代码少点,但是处理最小深度和最大深度稍微不太一样,不能直接把上面的代码改成min,当只有左子树和只有右子树的时候就会有问题。
// 72 ms 77.20%
// 37.2mb 69.67%
var minDepth = function(root) {
if (!root) return 0;
let res = null
let goDeep = function (parent, level) {
if (res && level > res) return; // 比最小大就可以不继续走下去了
if (!parent.left && !parent.right) {
if (!res || level < res) {
res = level
return
}
}
if (parent.left) {
goDeep(parent.left, level + 1)
}
if (parent.right) {
goDeep(parent.right, level + 1)
}
}
goDeep(root, 1)
return res
};
看了老师的代码,发现还能更简洁:
// 72 ms 77.20%
// 37.1mb 83.29%
var minDepth = function(root) {
if (!root) return 0;
let left = minDepth(root.left)
let right = minDepth(root.right)
return (left === 0 || right === 0 ? left + right + 1 : 1 + Math.min(left, right))
};
这个代码巧妙的处理了那种左右只有一边存在的情况,这种情况就不用min的方式,而用left + right + 1来返回,优雅。
22 括号生成
这个题暴力做法是有的,把所有排列组合都生成出来,然后一个个校验,校验括号的合法性之前用堆栈也做过了,所以,做肯定是可以做的,我一开始是这么想的。老师最后说的也是在这种方式上改进,当发现当前情况肯定是错误组合的情况下,停止递归下去。这种情况包括:
- 在准备生成右括号的时候,当前字符串中左括号的数量一定要大于右括号的数量。最简单的说,一开始就放一个右括号肯定是不对的。
- 括号要配对,那就意味着左右括号的数量要一样,等于给定的n
/**
* @param {number} n
* @return {string[]}
*/
// 64ms 81.72%
// 35mb 58.89%
var generateParenthesis = function(n) {
let res = []
let i = 0
let gen = function(left, right, substr) {
if (left === n && right === n) {
res[i++] = substr
return
}
if (left < n) {
gen(left + 1, right, substr + '(')
}
if (left > right && right < n) {
gen(left, right + 1, substr + ')')
}
}
gen(0, 0, '')
return res
};
这个代码看着真舒服,仔细琢磨这个过程,感觉递归真是神奇。