第三周

132 阅读6分钟

周一题目

  1. leetcode: 验证二叉树的前序序列化

    解题思路: 根据题目得知,叶子结点一点是“#”,前序遍历时,在最后一个节点之前,叶子节点的数量是小于等于非叶子节点的,遍历完成时,叶子节点数量比非叶子节点多一个,才符合题意;

      /**
      * @param {string} preorder
      * @return {boolean}
      */
      var isValidSerialization = function(preorder) {
        const nodes = preorder.split(',');
        const n = nodes.length;
        let count_num = 0;
        let count_null = 0;
        for (let i = 0; i < n; i++) {
            if (nodes[i] === '#') {
                count_null++;
            } else {
                count_num++;
            }
            if (count_null > count_num && i !== n - 1) {
                return false;
            }
        }
        return count_null - count_num === 1;
    
    
      };
    
  2. leetcode: 基本计算器II

    解题思路:遇到减号,就让这个数变负.遇到乘号,就让当前的数乘上之前的数.遇到除号,就让当前数被之前的数除.遇到乘法和除法,就更新到之前的数字的身上.加法和减法就好像分隔符,分隔出小的计算结果.需要一个栈,去存这些最后会做加法的计算结果。还要一个变量,记录上一个运算符是什么,它决定了怎么处理当前的数.最后将栈中的数进行累加即可

    var calculate = function(s) {
      const nums = [];
      let cur = 0;
      let prevOp = '+';
      s = s + '+';
      
      for (let i = 0; i < s.length; i++) {
        if (s[i] >= '0' && s[i] <= '9') {
          cur = cur * 10 + s[i].charCodeAt(0) -'0'.charCodeAt(0);
        } else if (s[i] == ' ') {
          continue;
        } else {
          if (prevOp == '+') { 
                    nums.push(cur)
                } else if (prevOp == '-') {
                    nums.push( -1 * cur) 
                } else if (prevOp == '*') {
                    nums[nums.length - 1] *=  cur 
                } else if (prevOp == '/') {
                    nums[nums.length - 1]  =  (nums[nums.length - 1] / cur) | 0
                }
                prevOp = s[i] 
                cur = 0 
        }
      }
        let sum = 0
        nums.forEach(v => {
            sum += v
        })
        return sum;
        };
    
  3. leetcode:函数的独占时间

    解题思路: 解构出每条log的信息 start:入栈end:出栈 累加耗时 end出栈后:栈不为空->存在父级->需要把父级函数的运行时间减掉当前运行时间

       /**
       * @param {number} n
       * @param {string[]} logs
       * @return {number[]}
       */
       var exclusiveTime = function(n, logs) {
           let stack = [];
           let result = new Array(n).fill(0);  // 保存运行时间
    
           for (let log of logs) {
             let [id, type, ts] = log.split(':');
             
             if (type === 'start') {
               stack.push({id, type,ts});
             } else {
               let duration = ts - stack.pop().ts + 1;
               result[id] += duration;
    
               let peekTop = stack[stack.length- 1];
               if (peekTop) {
                 result[peekTop.id] -= duration;
               }
             }
           }
    
           return result;
       };
    
  4. leetcode: 表现良好的最长时间段

    解题思路:定义一个前缀和数组,代表当前天以前所有工作时长 > 8小时的天数;那么前缀和数组 两个元素的差 > 0 就是表现良好的时间段,我们只需要求得两个前缀和元素之差的最大值.

      var longestWPI = function (hours) {
          let preSum = new Array(hours.length + 1).fill(0);
          for (let i = 1; i <= hours.length; i++) {
            if (hours[i-1] > 8) preSum[i] = preSum[i - 1] + 1
            else preSum[i] = preSum[i - 1] - 1
          }
          let max = 0
          for (let i = 0; i< preSum.length-1; i++){
            for (let j =i+1; j< preSum.length; j++){
                if (preSum[j] - preSum[i] >0){
                    max = Math.max(max, j-i);
                }
            }
          }
          return max
      };
    
    
  5. leetcode: 面试题 02.02. 返回倒数第 k 个节点

    解题思路:定义2个指针分别指向head,先让第一个指针走k步,然后2个指针一起走,当第一个指针走完后,第二个指针位置就是倒数第K个结点。

       /**
       * @param {ListNode} head
       * @param {number} k
       * @return {number}
       */
       var kthToLast = function(head, k) {
         let f = head;
         let kk = head;
         while(k-->0){
           f = f.next;
         };
         while(f !== null ){
           f=f.next;
           kk = kk.next;
         };
         return kk.val;
    
       };
        
    

周三题目

  1. leetcode: 剑指 Offer 22. 链表中倒数第k个节点

    解题思路:和上周的第5题相似,利用之前的思路进行代码编写

      /**
      * Definition for singly-linked list.
      * function ListNode(val) {
      *     this.val = val;
      *     this.next = null;
      * }
      */
      /**
      * @param {ListNode} head
      * @param {number} k
      * @return {ListNode}
      */
      var getKthFromEnd = function(head, k) {
        let first = head;
        let second = head;
        while(k-->0){
          first = first.next;
        };
        while(first!==null){
          first = first.next;
          second = second.next;
        };
        return second;
    
      };
      
    
  2. leetcode: 剑指 Offer 35. 复杂链表的复制

    解题思路:和12.6号给的题目相同,那么利用之前的思路先把原链表1->2->3 复制成1->1'->2->2'->3->3',然后分离出1->2->3, 1'->2'->3',后者就是复制出来的链表。

      /**
      * // Definition for a Node.
      * function Node(val, next, random) {
      *    this.val = val;
      *    this.next = next;
      *    this.random = random;
      * };
      */
    
      /**
      * @param {Node} head
      * @return {Node}
      */
      var copyRandomList = function(head) {
          if(head === null){
            return null;
          }
          let curr = head;
          // 第一步,1->1'->2->2'->3->3'
          while(curr){
            const newCurr = new Node(curr.val);
            newCurr.next = curr.next;
            curr.next = newCurr;
            curr = newCurr.next;
          };
          curr = head;
          while(curr){
            if(curr.random !== null){
              curr.next.random = curr.random.next; 
            }
            curr = curr.next.next;
          };
          // 分离1'->2'->3'
          const dummy = new Node(-1);
          let pre = dummy;
          curr = head;
          while(curr){
            pre.next = curr.next;
            pre = pre.next;
            curr.next = pre.next;
            curr = curr.next;
          }
          return dummy.next;
    
    
      };
    
  3. leetcode: 面试题 02.03. 删除中间节点

    解题思路:因为是删除中间结点,所以它肯定有前结点和后结点,当删除的结点的时候,相当于把后结点变成当前节点,然后跳过后节点,链接后后节点,这个时候就删除了当前节点。

      /**
      * @param {ListNode} node
      * @return {void} Do not return anything, modify node in-place instead.
      */
      var deleteNode = function(node) {
          node.val = node.next.val;
          node.next = node.next.next;
    
      };
      
    
  4. leetcode: 两数相加 II 

    解题思路:利用栈的规则,先入栈,最后再出栈的相加,超过10的计数。

      /**
      * @param {ListNode} l1
      * @param {ListNode} l2
      * @return {ListNode}
      */
      var addTwoNumbers = function(l1, l2) {
        let newL1 = [];
        let newL2 = [];
        while(l1){
           newL1.push(l1.val);
           l1 = l1.next;
         };
        while(l2){
           newL2.push(l2.val);
           l2 = l2.next;
         };
        let carry = 0;
        let ansList = null;
        while (newL1.length || newL2.length || carry !== 0) {//不断出栈
            const s1 = newL1.length ? newL1.pop() : 0;
            const s2 = newL2.length ? newL2.pop() : 0;
            let val = s1 + s2 + carry;
            carry = parseInt(val / 10);//计算进位
            val = val % 10;//计算当前节点的值
            const curNode = new ListNode(val);
            curNode.next = ansList;//向链表前插入新节点
            ansList = curNode;//重新赋值ansList
        }
        return ansList;
    
      };
    
  5. leetcode: 重排链表

    解题思路:将链表每个节点断开,存放到数组中。指针i从头到尾,指针j从尾到头,重新组建数组。

      var reorderList = function(head) {// 换行可删除,合并到4行
          let s = [];
          let tmp = null;
          while (head){
              tmp = head.next; 
              head.next = null; 
              s.push(head);
              head = tmp;
          } 
             
          let i = -1, j = s.length;
          while (++i < --j) {
            s[i].next = s[j];
            j !== i + 1 && (s[j].next = s[i + 1])
          }
              
          return s[0] 
      };
    
    

周五题目

  1. leetcode: 面试题 02.08. 环路检测

    解题思路:这道题目和之前给的一样,利用双指针进行判断。

      var detectCycle = function(head) {
        if(head === null){
            return null;
          }
          let fast = head;
          let slow = head;
          let start = head;
          let meet = null;
          while(fast !== null && fast.next !==null){
            //慢指针每次走一步
            slow = slow.next;
            //快指针每次走两步
            fast = fast.next.next;
            //如果相遇,说明有环,
            if (slow === fast) {
              meet = slow;
              break;
            }                 
          }
          if(meet === null) {
            return meet;
          }
          while(start !== meet){
            start = start.next;
            meet = meet.next;
          }
          return start;
      };
    
  2. leetcode: 设计链表

    解题思路:定义出单链表的构造函数,进行链表的操作,插入,获取,删除等常见的链表操作。

      var LinkNode = function (val, next) {
        this.val = val?val:0;
        this.next = next?next:null;
      }
      var MyLinkedList = function() {
          this.head = null;
          this.tail = null;
          this.size = 0;
      };
      MyLinkedList.prototype.getNode = function(index){
        if(index<0 || index>=this.size){
          return null;
        }
        var dummy = new LinkNode(0, this.head);
        while(index-->=0){
          dummy = dummy.next;
        }
        return dummy;
      };
    
      /** 
      * @param {number} index
      * @return {number}
      */
      MyLinkedList.prototype.get = function(index) {
          return this.getNode(index)? this.getNode(index).val: -1;
      };
    
      /** 
      * @param {number} val
      * @return {void}
      */
      MyLinkedList.prototype.addAtHead = function(val) {
         const dummy = new LinkNode(val, this.head);
         this.head = dummy;
         this.size ++;
         if(!this.tail){
           this.tail = dummy;
         }
      };
    
      /** 
      * @param {number} val
      * @return {void}
      */
      MyLinkedList.prototype.addAtTail = function(val) {
        const dummy = new LinkNode(val, null);
        this.size++;
        if(this.tail) {
            this.tail.next = dummy;
            this.tail = dummy;
            return;
        }
        this.tail = dummy;
        this.head = dummy;
      };
    
      /** 
      * @param {number} index 
      * @param {number} val
      * @return {void}
      */
      MyLinkedList.prototype.addAtIndex = function(index, val) {
        if(index>this.size){
          return;
        }
        if(index<=0){
          this.addAtHead(val);
          return;
        }
        if(index===this.size){
          this.addAtTail(val);
          return;
        }
        // 获取目标节点的上一个节点,进行插入,也就是next的指向。
         const node = this.getNode(index-1);
         node.next = new LinkNode(val, node.next);
         this.size++;
    
    
      };
    
      /** 
      * @param {number} index
      * @return {void}
      */
      MyLinkedList.prototype.deleteAtIndex = function(index) {
          if(index < 0 || index >= this.size) {
            return;
          }
          if(index === 0) {
              this.head = this.head.next;
              this.size--;
              return;
          }
          // 获取目标节点的上一个的节点
          const node = this.getNode(index - 1);    
          node.next = node.next.next;
          // 处理尾节点
          if(index === this.size - 1) {
              this.tail = node;
          }
          this.size--;
      };
    
      /**
      * Your MyLinkedList object will be instantiated and called as such:
      * var obj = new MyLinkedList()
      * var param_1 = obj.get(index)
      * obj.addAtHead(val)
      * obj.addAtTail(val)
      * obj.addAtIndex(index,val)
      * obj.deleteAtIndex(index)
      */
    
  3. leetcode: 剑指 Offer 18. 删除链表的节点

    解题思路:删除链表中的某个节点,也就是链表跳过该节点,链接不上,自然就删除了。

      var deleteNode = function(head, val) {
          if (head === null) return null;
          if (head.val === val) return head.next;
          let cur = head;
          while (cur.next  && cur.next.val !== val){
             cur = cur.next;
          }
          if (cur.next != null){
              cur.next = cur.next.next;
          }  
          return head;
        };
    
    
  4. leetcode: 分隔链表

    解题思路:首先第一步先遍历出链表的长度,然后长度除以k,然后再长度与k再取余,目的是为了除不尽的时候进行处理。

    /**
    * @param {ListNode} head
    * @param {number} k
    * @return {ListNode[]}
    */
    var splitListToParts = function(head, k) {
      let len = 0;
      let cur = head;
      let res = [];
      while(cur){
          len++;
          cur = cur.next;
      }
      let len1 = Math.floor(len/k);
      let plus = len % k;
      while(head){
          let count = plus > 0 ? len1+1:len1;
          cur = head;
          let pre = null;
          while(count > 0){
              pre = head;
              head = head.next;
              count--;
          }
          pre.next = null;
          res.push(cur);
          plus--;
      }
      while(res.length !==k){
          res.push(null);
      }
      return res;
    };
      
      
    
  5. leetcode: 面试题 02.04. 分割链表

    解题思路:和上次的题目一样。

      var partition = function(head, x) {
         if(head === null){
           return head;
         }
         const dummy = new ListNode(-1);
         dummy.next = head;
         let curr = head;
         let pre = dummy;
         if(curr.val< x){
             pre = curr;
         }
         while(curr&&curr.next){
           const next = curr.next;
           if(next.val < x && curr.val>=x) {
             curr.next = next.next;
             next.next =pre.next;
             pre.next = next;
           }else {
             curr = curr.next;
           }
           if(next.val<x){
              pre = next;
           }
           
         }
        
         return dummy.next;
    
      };