BFS && DFS
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 };
这个代码看着真舒服,仔细琢磨这个过程,感觉递归真是神奇。