周一题目
- 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; }; - 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; }; - 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; }; - 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) */ - 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; }
周三题目
- leetcode: 数组中的第K个最大元素
解题思路:和周一的题目相似,利用之前的理论进行编写代码
var findKthLargest = function(nums, k) { return nums.sort((a,b)=>b-a)[k-1]; }; - 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) */ - 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]) }; - 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() */ - 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; };
周五题目
-
解题思路:看题解,暂无思路
/** * @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); }; -
解题思路:首先了解丑数的定义,然后看了题解。。。。
/** * @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]; }; -
解题思路:
/** * @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] }; -
解题思路:没有找到规律~,看了题解
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) } }; -
解题思路:求解左右子树的最大深度的最大值,再加上根的,就是二叉树的最大深度了。
/** * 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; };