第六周学习笔记

87 阅读4分钟

周二题目

  1. leetcode: 面试题 04.05. 合法二叉搜索树

    解题思路: 首先二叉搜索树代表的是根节点比左叶节点大,比右节点数值小。根据中序排列,排列后如果是升序排列,就说明是合法的二叉树,反之则不是。

      /**
      * Definition for a binary tree node.
      * function TreeNode(val) {
      *     this.val = val;
      *     this.left = this.right = null;
      * }
      */
      /**
      * @param {TreeNode} root
      * @return {boolean}
      */
      var isValidBST = function(root) {
          if(!root)return true;
          let stack = [],res=[];
          let cur = root;
          while(stack.length || cur) {
              if(cur) {
                  stack.push(cur);
                  cur = cur.left;
              } else {
                  // --> 弹出 中
                  cur = stack.pop();
                  res.push(cur.val); 
                  // 右
                  cur = cur.right;
              }
          };
          let flag = true;
          for (let i = 0; i< res.length; i++) {
              if(i > 0) {
              if(res[i] <= res[i-1]) {
                  flag = false;
              }
              }
          }
          return flag;
    
    
      };
    
  2. leetcode: 二叉搜索树中第K小的元素

    解题思路:上次题目中要求求k大的元素,目前看k小,就是先看左子树,再看右子树,就是中序排列

      /**
      * @param {TreeNode} root
      * @param {number} k
      * @return {number}
      */
      var kthSmallest = function(root, k) {
          let ans;
          const inOrderTraverse = function(node) {
              if(node!=null && k>0) {
                  inOrderTraverse(node.left);
                  if(--k==0)
                      ans = node.val;
                  inOrderTraverse(node.right);
              }
          }
          inOrderTraverse(root);
          return ans;
      };
    
    
  3. leetcode: 二叉树的右视图

    解题思路: 层序遍历的时候,判断是否遍历到单层的最后面的元素,如果是,就放进result数组中,随后返回result就可以了

       var rightSideView = function(root) {
           //二叉树右视图 只需要把每一层最后一个节点存储到res数组
           let res=[],queue=[root];
           while(queue.length&&root!==null){
               // 记录当前层级节点个数
               let length=queue.length;
               while(length--){
                   let node=queue.shift();
                   //length长度为0的时候表明到了层级最后一个节点
                   if(!length){
                       res.push(node.val);
                   }
                   node.left&&queue.push(node.left);
                   node.right&&queue.push(node.right);
               }
           }
           return res;
       };
    
    
  4. leetcode: 相同的树

    解题思路:2颗树进行递归,如果相同的话,每个节点都会相同,如果不同,则不是相同的树

      /**
      * @param {TreeNode} p
      * @param {TreeNode} q
      * @return {boolean}
      */
      var isSameTree = function(p, q) {
          if(p===null && q===null){
          return true ;
          }
          if(p=== null || q=== null){
              return false;
          }
          if(p.val !== q.val){
              return false;
          }
          return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
    
      };     
    
  5. leetcode: 对称二叉树

    解题思路:根据题意,使用迭代法进行书写

       var isSymmetric = function(root) {
           //迭代方法判断是否是对称二叉树
           //首先判断root是否为空
           if(root===null){
               return true;
           }
           let queue=[];
           queue.push(root.left);
           queue.push(root.right);
           while(queue.length){
               let leftNode=queue.shift();//左节点
               let rightNode=queue.shift();//右节点
               if(leftNode===null&&rightNode===null){
                   continue;
               }
               if(leftNode===null||rightNode===null||leftNode.val!==rightNode.val){
                   return false;
               }
               queue.push(leftNode.left);//左节点左孩子入队
               queue.push(rightNode.right);//右节点右孩子入队
               queue.push(leftNode.right);//左节点右孩子入队
               queue.push(rightNode.left);//右节点左孩子入队
           }
           return true;
       };
        
    

周四题目

  1. leetcode: 剑指 Offer 68 - I. 二叉搜索树的最近公共祖先

    解题思路:由于是二叉搜索树,所以如果一个比我小,一个比我大就返回我;都比我大就递归我的右边,都比我小就递归我的左边

      var lowestCommonAncestor = function(root, p, q) {
            if(!root || root===p || root===q || (root.val > p.val && root.val < q.val)  || (root.val < p.val && root.val > q.val)) return root;
            if(root.val > p.val && root.val > q.val) return lowestCommonAncestor(root.left, p, q);
            if(root.val < p.val && root.val < q.val) return lowestCommonAncestor(root.right, p, q);
        };
    
    
  2. leetcode: 二叉树中的最大路径和

    解题思路:路径每到一个节点,都会有3种情况,1)停在当前 2)往左侧走 3)往右侧走。 2和3之后,又是这3种情况。但是不能返回,返回不符合题意。所以停在当前最大收益root.val,情况2: root.val+ dfs(root.left) 情况3: root.val+dfs(root.right); 而最大收益就是root.val+max(0, dfs(root.left), dfs(root.right))

      const maxPathSum = (root) => {
          let maxSum = Number.MIN_SAFE_INTEGER; // 最大路径和
    
          const dfs = (root) => {
              if (root == null) { // 遍历到null节点,收益0
              return 0;
              }
              const left = dfs(root.left);   // 左子树提供的最大路径和
              const right = dfs(root.right); // 右子树提供的最大路径和
    
              const innerMaxSum = left + root.val + right; // 当前子树内部的最大路径和
              maxSum = Math.max(maxSum, innerMaxSum);      // 挑战最大纪录
    
              const outputMaxSum = root.val + Math.max(0, left, right); // 当前子树对外提供的最大和
    
              // 如果对外提供的路径和为负,直接返回0。否则正常返回
              return outputMaxSum < 0 ? 0 : outputMaxSum;
          };
    
          dfs(root);  // 递归的入口
    
          return maxSum; 
      };
    
    
  3. leetcode: 前 K 个高频元素

    解题思路:先判断给定元素其中某个值出现的次数,再根据出现的次数进行排序,截取前k个高频元素,就得到以下的程序代码。

      /**
      * @param {number[]} nums
      * @param {number} k
      * @return {number[]}
      */
      var topKFrequent = function(nums, k) {
          if(!nums.length ){
              return nums;
          }
          let m = new Map();
          nums.forEach(i=>{
              let count =1;
    
              if(m.has(i)){
                  count=m.get(i);
                  count++;
              }
              
              m.set(i,count);
          });
    
          let r = [];
          for (let [key, value] of m) {
              r.push({key,value});
          }
          
          r= r.sort((a,b)=>b.value-a.value).splice(0,k).map(i=>i.key);
          return r;
      };
      
    
  4. leetcode: 最接近原点的 K 个点

    解题思路:首先了解欧几里德距离。定义:欧几里得度量(euclidean metric)(也称欧氏距离)是一个通常采用的距离定义,指在m维空间中两个点之间的真实距离,或者向量的自然长度(即该点到原点的距离)。在二维和三维空间中的欧氏距离就是两点之间的实际距离。二维公式是:Math.hypot(x1 - x0, y1 - y0);

      /**
      * @param {number[][]} points
      * @param {number} k
      * @return {number[][]}
      */
      var kClosest = function(points, k) {
          // 由于是距离远点之间的距离,可以之间简写成如下
          let pp = [];
          points.forEach((p)=>{
              const distance = Math.hypot(p[0], p[1]);
              pp.push({
                  d:distance,
                  i:p
              });
          })
          pp = pp.sort((a,b)=>a.d-b.d).splice(0,k).map(i=>i.i);
          return pp;
          
      };
      
    
  5. leetcode: 根据字符出现频率排序

    解题思路:和第3题的思路比较相似,先把字符串转成数组,再对比第三题的循环塞入一个新的数组,再转成字符串。

      /**
      * @param {string} s
      * @return {string}
      */
      var frequencySort = function(s) {
          if(!s.length ){
              return s;
          }
          let m = new Map();
          let sN = s.split("");
          sN.forEach(i=>{
              let count =1;
    
              if(m.has(i)){
                  count=m.get(i);
                  count++;
              }
              
              m.set(i,count);
          });
          let r = [];
          for (let [key, value] of m) {
              for(let i=0;i<value;i++){
                   r.push({key,value});
              }
             
          }
          r= r.sort((a,b)=>b.value-a.value).map(i=>i.key);
          return r.join("");
      };