第五周学习

85 阅读6分钟

周一题目

  1. leetcode: 平衡二叉树

    解题思路: 首先理解平衡二叉树的含义:任何一个结点的左子树与右子树都是平衡二叉树,并且高度之差的绝对值不超过1。

      /**
      * @param {TreeNode} root
      * @return {boolean}
      */
      var isBalanced = function(root) {
          let flag = true;
          const maxDept = (root)=>{
              if(root===null)return 0;
              let leftDept = maxDept(root.left);
              let rightDept = maxDept(root.right);
              if(Math.abs(leftDept-rightDept)>1){
                  flag = false;
              }
              return 1+ Math.max(leftDept, rightDept);
          }
          maxDept(root);
          return flag;
      };
     
    
  2. leetcode: 剑指 Offer 40. 最小的k个数

    解题思路:求输入数组的最小K个数,我们可以先将数组按照从小到大进行排序,然后数组进行循环push到新数组,循环次数为k;

      var getLeastNumbers = function(arr, k) {
          const newArr = arr.sort((a,b)=>a-b);
          const newPush = [];
          while(k--){
              newPush.push(newArr[k]);
          }
          return newPush;
    
      };
    
  3. leetcode:  最后一块石头的重量

    解题思路: 先sort排序找出最大的2个值,进行相减,返回大于0的,插入数组,然后再次进行递归。

       /**
       * @param {number[]} stones
       * @return {number}
       */
       var lastStoneWeight = function(stones) {
           stones.sort((a,b)=>a-b);
           if (stones.length > 1) {
               const d = stones.pop() - stones.pop();
               if (d) {
                   stones.push(d);
               }
               return lastStoneWeight(stones);
           }
           return stones[0]?stones:0;
       };
    
  4. leetcode: 数据流中的第 K 大元素

    解题思路:当数据流有新的元素的时候,重新按升序排序数组,倒数第k个元素就是第k大的数.

       /**
      * @param {number} k
      * @param {number[]} nums
      */
      var KthLargest = function(k, nums) {
          this.nums = nums.sort((a,b)=>b-a);
          this.k = k;
      };
    
      /** 
      * @param {number} val
      * @return {number}
      */
      KthLargest.prototype.add = function(val) {
          this.nums.push(val);
          return this.nums.sort((a,b)=>b-a)[this.k-1];
      };
    
      /**
      * Your KthLargest object will be instantiated and called as such:
      * var obj = new KthLargest(k, nums)
      * var param_1 = obj.add(val)
      */       
    
  5. leetcode: 查找和最小的K对数字

    解题思路:由于nums1和nums2已经排好顺序(升序),我们只需要重新组合,然后找出前k的组合值。(补充:因为nums1和nums2 有可能是相同的大小数组,即1,1,2 和 1,2,3 ,这个时候重新组合的时候再次进行排序)

       /**
       * @param {number[]} nums1
       * @param {number[]} nums2
       * @param {number} k
       * @return {number[][]}
       */
       var kSmallestPairs = function(nums1, nums2, k) {
           let n = [];
           for(let i=0;i<nums1.length; i++){
               for(let j=0;j<nums2.length; j++){
                   n.push([nums1[i],nums2[j]]);
               }
           }
           return n.splice(0,k);
       };
    
       /*
       * 正确答案
       */
       var kSmallestPairs = function(nums1, nums2, k) {
           const res = [], minStack = [];
           for (let i = Math.min(k, nums1.length) - 1; i > -1; i--) minStack.push([i, 0]);
    
           while (res.length < k && minStack.length) {
               const [i, j] = minStack.pop();
               res.push([nums1[i], nums2[j]]);
    
               if (j + 1 >= nums2.length) continue;
               const len = minStack.length;
               for (let m = len - 1; m > -1; m--) {
                   const [i1, j1] = minStack[m];
                   if (nums1[i1] + nums2[j1] >= nums1[i] + nums2[j + 1]) {
                       minStack.splice(m + 1, 0, [i, j + 1]);
                       break;
                   }
               }
               if (len === minStack.length) minStack.unshift([i, j + 1]);
           }
    
           return res;
    
       }
    
        
    

周三题目

  1. leetcode: 数组中的第K个最大元素

    解题思路:和周一的题目相似,利用之前的理论进行编写代码

      var findKthLargest = function(nums, k) {
        return nums.sort((a,b)=>b-a)[k-1];
    };
    
  2. leetcode: 设计推特

    解题思路:开始思考还是比较顺利,但是鲁棒性需要多考虑,注释在题目里面

      var Twitter = function() {
          // 保存用户和用户发送的推文信息
          this.postTweetMap = {};
          // 保存关注的信息
          this.followMap = {};
          // count 计数
          this.count = 0;
      };
    
      /** 
      * @param {number} userId 
      * @param {number} tweetId
      * @return {void}
      */
      Twitter.prototype.postTweet = function(userId, tweetId) {
          // 题目要求按照时间顺序由最近到最远进行排序,单个的可以做到,但是有follow 的就不可以,所以再加上一个字段,进行计数
          this.count++;
          this.postTweetMap[userId] = [{
              count:this.count,
              mes:tweetId
          }, ...(this.postTweetMap[userId]|| [])];
    
      };
    
      /** 
      * @param {number} userId
      * @return {number[]}
      */
      Twitter.prototype.getNewsFeed = function(userId) {
          //先得到自己发的推特信息
          let all = [];
          let self= this.postTweetMap[userId]|| [];
          // 看看是否follow了其他人
          const other = this.followMap[userId];
          const l = other? other.length:0;
          if(l>0){
              const otherAll = [];
              for(let i = 0;i<l;i++){
                  if(this.postTweetMap[other[i]]){
                      otherAll.push(this.postTweetMap[other[i]]);
                  }
              
              }
              const aflat =otherAll.flat() || [];
              self = self.concat(aflat);
              
          }
          self.sort((a,b)=>b.count-a.count);
          all =self.slice(0,10).map(it=>it.mes);
          return all;
      };
    
      /** 
      * @param {number} followerId 
      * @param {number} followeeId
      * @return {void}
      */
      Twitter.prototype.follow = function(followerId, followeeId) {
          this.followMap[followerId]=Array.from(new Set([followeeId, ...(this.followMap[followerId]?this.followMap[followerId]:[])]));
      };
    
      /** 
      * @param {number} followerId 
      * @param {number} followeeId
      * @return {void}
      */
      Twitter.prototype.unfollow = function(followerId, followeeId) {
          const l =  this.followMap[followerId];
          if(l){
              this.followMap[followerId]= l.filter(i=>i!==followeeId);
          }
      
      };
    
      /**
      * Your Twitter object will be instantiated and called as such:
      * var obj = new Twitter()
      * obj.postTweet(userId,tweetId)
      * var param_2 = obj.getNewsFeed(userId)
      * obj.follow(followerId,followeeId)
      * obj.unfollow(followerId,followeeId)
      */
    
  3. leetcode: 前K个高频单词

    解题思路:解题思路在注释中,一开始按照数组,相同单词,就加上1,但是发现排序的时候,相同出现的数量,根据单词进行排序没有弄好,看了注解发现更加简单的做法。

      /**
      * @param {string[]} words
      * @param {number} k
      * @return {string[]}
      */
      var topKFrequent = function(words, k) {
      if(!words.length){
          return []
      }
      let obj = [];
    
      let ab = [...new Set(words)];
      words.sort();
      console.log(words)
      for(let i=0; i<ab.length;i++){
          let c = 1;
          for(let j=0;j<words.length;j++){
              if(ab[i]===words[j]){
                  // 判断是否已经在数组中
                  const l = obj.findIndex(ii=>ii.name===words[j]);
                  if(l>-1){
                      obj[l].count = c++;
                  }else{
                      obj.push({
                              count: c++,
                              name: words[j]
                          });
                  }
                  
                  
              }
          }
      }
    
      obj = obj.sort((a,b)=> b.count-a.count});
      
      obj = obj.map(i=>i.name);
      return obj
    
      
    
      };
      //差了一点,正确答案下方
    
      var topKFrequent = function(words, k) {
          // 1. 统计所有单词出现的频率
          let map = new Map()
          for (let word of words) {
              map.set(word, (map.get(word) || 0) + 1)
          }
          // 2. 根据单词出现频率和字母表进行排序
          let arr = Array.from(map)
          arr.sort((a, b) => b[1] === a[1] ? a[0].localeCompare(b[0]) : b[1] - a[1])
          // 3. 过滤出最前面 k 个数据
          let top = arr.slice(0, k)
          // 4. 转换为所需数据结构
          return top.map(a => a[0])
      };
    
      
    
  4. leetcode: 面试题 17.20. 连续中值

    解题思路:根据题意,可以写出简单代码。但是耗时较长,等待优化。

      /**
      * initialize your data structure here.
      */
      var MedianFinder = function() {
          this.mapData = [];
      };
    
      /** 
      * @param {number} num
      * @return {void}
      */
      MedianFinder.prototype.addNum = function(num) {
          this.mapData.push(num);
          this.mapData.sort((a,b)=>a-b);
      };
    
      /**
      * @return {number}
      */
      MedianFinder.prototype.findMedian = function() {
          const l  = this.mapData.length;
          let num = 0;
          if(l>0){
              if(l%2===0){
                  num = (this.mapData[l/2]+this.mapData[l/2-1])/2
    
              }else {
                  let i = (l-1)/2;
                  num = this.mapData[i];
              }
    
          }
          return num;
      };
    
      /**
      * Your MedianFinder object will be instantiated and called as such:
      * var obj = new MedianFinder()
      * obj.addNum(num)
      * var param_2 = obj.findMedian()
      */
      
    
  5. leetcode: 数据流的中位数

    解题思路:和上一题相似,但是提出了更高的要求,目前没想到,先用上一题的答案顶着(但是运行leetcode提示已超出时间限制)

      /**
      * initialize your data structure here.
      */
      var MedianFinder = function() {
          this.mapData = [];
      };
    
      /** 
      * @param {number} num
      * @return {void}
      */
      MedianFinder.prototype.addNum = function(num) {
          this.mapData.push(num);
          this.mapData.sort((a,b)=>a-b);
      };
    
      /**
      * @return {number}
      */
      MedianFinder.prototype.findMedian = function() {
          const l  = this.mapData.length;
          let num = 0;
          if(l>0){
              if(l%2===0){
                  num = (this.mapData[l/2]+this.mapData[l/2-1])/2
    
              }else {
                  let i = (l-1)/2;
                  num = this.mapData[i];
              }
    
          }
          return num;
      };
    

周五题目

  1. leetcode: 积压订单中的订单总数

    解题思路:看题解,暂无思路

        /**
        * @param {number[][]} orders
        * @return {number}
        */
        function heapifyMax(arr, i, len) {
            let left = i * 2 + 1;
            let right = i * 2 + 2;
            let max = i;
            if (left < len && arr[left].price > arr[max].price) {
                max = left;
            }
            if (right < len && arr[right].price > arr[max].price) {
                max = right;
            }
            if (i !== max) {
                let tmp = arr[i];
                arr[i] = arr[max];
                arr[max] = tmp;
    
                heapifyMax(arr, max, len);
            }
        }
    
        function heapifyMin(arr, i, len) {
            let left = i * 2 + 1;
            let right = i * 2 + 2;
            let min = i;
            if (left < len && arr[left].price < arr[min].price) {
                min = left;
            }
            if (right < len && arr[right].price < arr[min].price) {
                min = right;
            }
            if (i !== min) {
                let tmp = arr[i];
                arr[i] = arr[min];
                arr[min] = tmp;
    
                heapifyMin(arr, min, len);
            }
        }
        var getNumberOfBacklogOrders = function(orders) {
            let buyStack = [];
            let sellStack = [];
            for (let i = 0; i < orders.length; i++) {
                if (orders[i][2] == 0) {
                    buyStack.push({
                        num: orders[i][1],
                        price: orders[i][0]
                    });
                    // 插入操作  从最后面插  然后从底向上交换父元素  只交换那一条链
                    let index = buyStack.length - 1;
                    let father = (((index + 1) >> 1) - 1);
    
                    while (father >= 0 && buyStack[father].price < buyStack[index].price) {
                        let tmp = buyStack[father];
                        buyStack[father] = buyStack[index];
                        buyStack[index] = tmp;
    
                        index = father;
                        father = (((index + 1) >> 1) - 1);
                    }
                    // 插入操作  从最后面插  然后从底向上交换父元素
                    // 只交换父元素那一条链就可以..  但我重新buildHeap也没事儿..
                    // for (let tmp = ((buyStack.length >> 1) - 1); tmp >= 0; tmp--) {
                    //     heapifyMax(buyStack, tmp, buyStack.length);
                    // }
                } else {
                    sellStack.push({
                        num: orders[i][1],
                        price: orders[i][0]
                    });
    
                    let index = sellStack.length - 1;
                    let father = (((index + 1) >> 1) - 1);
    
                    while (father >= 0 && sellStack[father].price > sellStack[index].price) {
                        let tmp = sellStack[father];
                        sellStack[father] = sellStack[index];
                        sellStack[index] = tmp;
    
                        index = father;
                        father = (((index + 1) >> 1) - 1);
                    }
    
                    // for (let tmp = ((sellStack.length >> 1) - 1); tmp >= 0; tmp--) {
                    //     heapifyMin(sellStack, tmp, sellStack.length);
                    // }
                }
                helper();
            }
    
            function helper() {
                while (buyStack.length && sellStack.length) {
                    if (buyStack[0].price >= sellStack[0].price) {
    
                        let num = Math.min(buyStack[0].num , sellStack[0].num);
    
                        buyStack[0].num -= num;
                        if (buyStack[0].num == 0) {
                            // 删除操作 不能直接扔掉堆顶 也就是说:不能直接shift()
                            // 把底部的一个元素拿上来.. 替换堆顶元素  然后pop() 类似于把堆顶shift了  然后heapify(0)
                            buyStack[0] = buyStack[buyStack.length - 1];
                            buyStack.pop();
                            heapifyMax(buyStack, 0, buyStack.length);
                        }
    
                        sellStack[0].num -= num;
                        if (sellStack[0].num == 0) {
                            sellStack[0] = sellStack[sellStack.length - 1];
                            sellStack.pop();
                            heapifyMin(sellStack, 0, sellStack.length);
                        }
                    } else {
                        break;
                    }
                }
            }
            let ret = 0;
            for (let i = 0; i < buyStack.length; i++) {
                ret += buyStack[i].num;
            }
            for (let i = 0; i < sellStack.length; i++) {
                ret += sellStack[i].num;
            }
            return ret % (1000000007);
        };
    
      
    
  2. leetcode: 丑数 II

    解题思路:首先了解丑数的定义,然后看了题解。。。。

      /**
      * @param {number} n
      * @return {number}
      */
      var nthUglyNumber = function(n) {
          const dp = new Array(n + 1).fill(0);
          dp[1] = 1;
          let p2 = 1, p3 = 1, p5 = 1;
          for (let i = 2; i <= n; i++) {
              const num2 = dp[p2] * 2, num3 = dp[p3] * 3, num5 = dp[p5] * 5;
              dp[i] = Math.min(Math.min(num2, num3), num5);
              if (dp[i] === num2) {
                  p2++;
              }
              if (dp[i] === num3) {
                  p3++;
              }
              if (dp[i] === num5) {
                  p5++;
              }
          }
          return dp[n];
      };
    
      
    
  3. leetcode: 超级丑数

    解题思路:

     /**
      * @param {number} n
      * @param {number[]} primes
      * @return {number}
      */
      var nthSuperUglyNumber = function(n, primes) {
      let a= new Array(primes.length).fill(1)
      let b= new Array(n+1).fill(0)
      b[1]=1
      for(var i=2;i<=n;i++){
          let min=Infinity
          for(var j=0;j<a.length;j++){
              min=Math.min(min,b[a[j]]*primes[j])
          }
          for(var k=0;k<a.length;k++){
              if(min===b[a[k]]*primes[k]){
                  a[k]++
              }
          }
          b[i]=min
      }
      return b[b.length-1]
      };
    
    
    
  4. leetcode: 移除石子的最大得分

    解题思路:没有找到规律~,看了题解

      var maximumScore = function(a, b, c) {
          let stone = [a,b,c]
          stone.sort((a,b)=>a-b)
          two = stone[0]+stone[1]
          if(two<=stone[2]){
              return two
          }else{
              return parseInt((two+stone[2])/2)
          }
    
      };
    
  5. leetcode: 二叉树的最大深度

    解题思路:求解左右子树的最大深度的最大值,再加上根的,就是二叉树的最大深度了。

      /**
      * Definition for a binary tree node.
      * function TreeNode(val, left, right) {
      *     this.val = (val===undefined ? 0 : val)
      *     this.left = (left===undefined ? null : left)
      *     this.right = (right===undefined ? null : right)
      * }
      */
      /**
      * @param {TreeNode} root
      * @return {number}
      */
      var maxDepth = function(root) {
          if(null == root){
              return 0;
          }
          //单层逻辑
          //左子树的深度和右子树的深度最大的值+1就是二叉树的深度
    
          //传递参数
          //传入root,返回深度
          return Math.max(maxDepth(root.left),maxDepth(root.right)) + 1;
    
      };