第四周

113 阅读6分钟

周一题目

  1. 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);
          }
    
    
      };
    
  2. 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);
      }
    
  3. 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;
       };
      
    
  4. 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;
    
      };       
    
  5. 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);
       };
    
        
    

周三题目

  1. 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);
        }      
    
  2. 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);
      }
    
  3. 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
                  
      };
    
  4. 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)
          }
      };
    
      
    
  5. 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;
      }
    

周五题目

  1. leetcode: N 叉树的前序遍历

    解题思路:根据二叉树的前序遍历,实际上就是在多一层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;
        };
    
      
    
  2. leetcode: 翻转二叉树

    解题思路:用当前节点的左右子树进行交换,然后再递归。

      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;
      };
    
  3. 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;
      };
    
    
  4. leetcode: 二叉树的层序遍历 II

    解题思路:利用上一题的结果进行反转,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();
      };
    
  5. leetcode: 二叉树的锯齿形层序遍历

    解题思路:利用上一题的逻辑进行编写,但是利用双端队列,进行转换。

      /**
      * @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;
      };