周一题目
- leetcode: 第K个语法符号
解题思路: 咋一看简单的递归,但是根据规律,每一行的前半段就是上一行,后半段是上一行的值的反转(0->1,1->0)。
/** * @param {number} n * @param {number} k * @return {number} */ var kthGrammar = function(n, k) { if(n===1){ return 0; } let l = 2**(n-1);//当前行的长度。 if(k>l/2){ let val = kthGrammar(n-1, k-l/2); // 先得到上一行的值,位置是k相对于后半段的位置 return val ? 0:1;// 把值进行反过来 }else { // 如果是前半段 return kthGrammar(n-1,k); } }; - leetcode: 剑指 Offer 10- I. 斐波那契数列
解题思路:利用尾递归进行代码编写
/** * @param {number} n * @return {number} */ var fib = function(n) { return fibTail(0,1,n); }; function fibTail(a, b, n){ // a->F(0) b -> F(1) if(n===0){ return a; } return fibTail(b, (a+b)%1000000007, n-1); } - leetcode: 路径总和
解题思路: 遍历二叉树从根节点到叶子节点的数值和是不是等于给定的数值,利用非递归实现(迭代)
/** * @param {TreeNode} root * @param {number} targetSum * @return {boolean} */ var hasPathSum = function(root, targetSum) { if(root === null){ return false; } const stack = [root]; const res = [root.val]; while(stack.length){ const top = stack.pop(); const temp = res.pop(); if(top.left===null && top.right===null){ if(temp===targetSum){ return true; } } if(top.left){ stack.push(top.left); res.push(temp+top.left.val); } if(top.right){ stack.push(top.right); res.push(temp+top.right.val); } }; return false; }; - leetcode: 从前序与中序遍历序列构造二叉树
解题思路:前序排列中第一个元素为中间节点,还要找切割点,要切割前序排列的数组,得到左右2边,切割中序排列,得到左右2边,注意不管是前序还是中序数组的大小是相同的。
var buildTree = function(preorder, inorder) { if(!inorder.length){ return null; } const root = new TreeNode(preorder[0]); const index = inorder.findIndex(number=>number===root.val); root.left = buildTree(preorder.slice(1,index+1),inorder.slice(0,index)); root.right = buildTree(preorder.slice(index + 1, preorder.length), inorder.slice(index + 1, inorder.length)); return root; }; - leetcode: 完全二叉树的节点个数
解题思路:满二叉树的结点是Math.pow(2,h)-1,普通的二叉树结点可以根据前后中的递归顺序进行求和。
/** * @param {TreeNode} root * @return {number} */ var countNodes = function (root) { // 记录左、右子树的高度 let hl = 0, hr = 0; let l = root, r = root; // 计算左子树高 while (l) { l = l.left; hl++; } // 计算右子树高 while (r) { r = r.right; hr++; } // 如果左右子树的高度相同,则是一棵满二叉树 if (hl == hr) { return Math.pow(2, hl) - 1; } // 如果左右高度不同,则按照普通二叉树的逻辑计算,两个递归只有一个会真的递归下去,另一个一定会触发hl == hr而立即返回,不会递归下去 return 1 + countNodes(root.left) + countNodes(root.right); };
周三题目
- leetcode: 剑指 Offer 54. 二叉搜索树的第k大节点
解题思路:二叉查找树,又被称为二叉搜索树。其特点如下:设x为二叉查找树中的一个结点,x节点包含关键字key,一句话就是左孩子比父节点小,右孩子比父节点大,还有一个特性就是”中序遍历“可以让结点有序.题目中说是第K大的节点,意味着中序排列的倒序,中序排列为左中右,排好后进行翻转即可(右中左)。
/** * @param {TreeNode} root * @param {number} k * @return {number} */ let res,n; var kthLargest = function(root, k) { n=k; dfs(root); return res; }; function dfs(root){ if(root===null|| n<=0){ return } dfs(root.right); if(--n===0){ res = root.val; return } dfs(root.left); } - leetcode: 剑指 Offer 26. 树的子结构
解题思路:判断B树是否为A树的子结构,先去获取B树的根节点,再去A树中去找到对应的节点与B树的根节点进行对比,如果有,再进行对比剩余节点是否相同。
/** * @param {TreeNode} A * @param {TreeNode} B * @return {boolean} */ var isSubStructure = function(A, B) { if(A===null || B===null) return false; if(helper(A,B)) return true; return isSubStructure(A.left,B) || isSubStructure(A.right,B); }; function helper(A,B){ if(B===null) return true; if(A===null || A.val!==B.val) return false; return helper(A.left,B.left) && helper(A.right,B.right); } - leetcode: 监控二叉树
解题思路:不理解
var minCameraCover = function(root) { let result = 0 function traversal(cur) { if(cur === null) { return 2 } let left = traversal(cur.left) let right = traversal(cur.right) if(left === 2 && right === 2) { return 0 } if(left === 0 || right === 0) { result++ return 1 } if(left === 1 || right === 1) { return 2 } return -1 } if(traversal(root) === 0) { result++ } return result }; - leetcode: 二叉树最大宽度
解题思路:题目和题解都没看懂
var widthOfBinaryTree = function(root) { if (!root) return 0; let res = [], max = 1n; recusion(root, 0, 0n); return max; function recusion (node, level, num) { if(!res[level]) res.push([]) res[level].push(num) // 计算最大宽度 var tempArr = res[level] console.log(tempArr[tempArr.length - 1], tempArr[0]) var tempWidth = tempArr[tempArr.length - 1] - tempArr[0] + 1n; if(tempWidth > max) max = tempWidth console.log(num) if(node.left) recusion(node.left, level + 1, num * 2n ) if(node.right) recusion(node.right, level + 1, num * 2n + 1n) } }; - leetcode: 二叉树的前序遍历
解题思路:二叉树的前序排序中左右,可利用递归的方式和迭代法进行,题目要求用迭代法
/** * 递归 * @param {TreeNode} root * @return {number[]} */ var preorderTraversal = function(root, r=[]) { const res = r; if(root === null){ return res; } res.push(root.val); preorderTraversal(root.left, res); preorderTraversal(root.right, res); return res; };/** * 迭代 * @param {TreeNode} root * @return {number[]} */ //入栈 右->左 // 出栈 中-> 左 -> 右 var preorderTraversal = function(root, r=[]) { const res = r; if(root === null){ return res; } let curr = null; const stack = [root]; while(stack.length){ curr = stack.pop(); res.push(curr.val); curr.right&& stack.push(curr.right); curr.left && stack.push(curr.left); } return res; }
周五题目
-
解题思路:根据二叉树的前序遍历,实际上就是在多一层chilren
/** * @param {Node|null} root * @return {number[]} */ var preorder = function(root) { if (root == null) return output; const stack = [root]; const output = []; while (stack.length) { const node = stack.pop(); output.push(node.val); node.children.reverse(); stack.push(...node.children); } return output; }; -
解题思路:用当前节点的左右子树进行交换,然后再递归。
var invertTree = function(root) { if(root===null) { return null; } //下面三句是将当前节点的左右子树交换 let tmp = root.right; root.right = root.left; root.left = tmp; //递归交换当前节点的 左子树 invertTree(root.left); //递归交换当前节点的 右子树 invertTree(root.right); //函数返回时就表示当前这个节点,以及它的左右子树 //都已经交换完了 return root; }; -
leetcode: 剑指 Offer 32 - II. 从上到下打印二叉数II
解题思路:利用队列的先进先出,符合一层一层遍历的逻辑,而是用栈先进后出适合模拟深度优先遍历也就是递归的逻辑
var levelOrder = function(root) { //二叉树的层序遍历 let res=[],queue=[]; queue.push(root); if(root===null){ return res; } while(queue.length!==0){ // 记录当前层级节点数 let length=queue.length; //存放每一层的节点 let curLevel=[]; for(let i=0;i<length;i++){ let node=queue.shift(); curLevel.push(node.val); // 存放当前层下一层的节点 node.left&&queue.push(node.left); node.right&&queue.push(node.right); } //把每一层的结果放到结果数组 res.push(curLevel); } return res; }; -
解题思路:利用上一题的结果进行反转,reverse方法
var levelOrderBottom = function(root) { let res=[],queue=[]; queue.push(root); if(root===null){ return res; } while(queue.length!==0){ // 记录当前层级节点数 let length=queue.length; //存放每一层的节点 let curLevel=[]; for(let i=0;i<length;i++){ let node=queue.shift(); curLevel.push(node.val); // 存放当前层下一层的节点 node.left&&queue.push(node.left); node.right&&queue.push(node.right); } //把每一层的结果放到结果数组 res.push(curLevel); } return res.reverse(); }; -
解题思路:利用上一题的逻辑进行编写,但是利用双端队列,进行转换。
/** * @param {TreeNode} root * @return {number[][]} */ var zigzagLevelOrder = function(root) { let res=[],queue=[]; queue.push(root); if(root===null){ return res; } let isF = true; while(queue.length!==0){ // 记录当前层级节点数 let length=queue.length; //存放每一层的节点 let curLevel=[]; for(let i=0;i<length;i++){ let node=queue.shift(); if(isF){ curLevel.push(node.val); }else { curLevel.unshift(node.val); } // 存放当前层下一层的节点 node.left&&queue.push(node.left); node.right&&queue.push(node.right); } //把每一层的结果放到结果数组 res.push(curLevel); isF = !isF; } return res; };