周一题目
-
解题思路: 根据题目得知,叶子结点一点是“#”,前序遍历时,在最后一个节点之前,叶子节点的数量是小于等于非叶子节点的,遍历完成时,叶子节点数量比非叶子节点多一个,才符合题意;
/** * @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; }; -
解题思路:遇到减号,就让这个数变负.遇到乘号,就让当前的数乘上之前的数.遇到除号,就让当前数被之前的数除.遇到乘法和除法,就更新到之前的数字的身上.加法和减法就好像分隔符,分隔出小的计算结果.需要一个栈,去存这些最后会做加法的计算结果。还要一个变量,记录上一个运算符是什么,它决定了怎么处理当前的数.最后将栈中的数进行累加即可
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; }; -
解题思路: 解构出每条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; }; -
解题思路:定义一个前缀和数组,代表当前天以前所有工作时长 > 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 }; -
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; };
周三题目
- 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; }; - 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; }; - 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; }; - 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; }; - 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] };
周五题目
-
解题思路:这道题目和之前给的一样,利用双指针进行判断。
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; }; -
解题思路:定义出单链表的构造函数,进行链表的操作,插入,获取,删除等常见的链表操作。
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) */ -
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; }; -
解题思路:首先第一步先遍历出链表的长度,然后长度除以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; }; -
解题思路:和上次的题目一样。
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; };