刷题Day2
依然是数组类的题目!
有序数组的平方
-
一开始直接想到了暴力 平方然后排序,注意map返回的是新函数喔!!
这个时间复杂度是 O(n + nlogn), 可以说是O(nlogn)的时间复杂度。
-
// var sortedSquares = function(nums) { // let newArr = nums.map(item => { // return item*item // }) // return newArr.sort((a,b) => a-b) // };
-
双指针方法
-
数组其实是有序的, 只不过负数平方之后可能成为最大数了。
那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。
此时可以考虑双指针法了,i指向起始位置,j指向终止位置。
var sortedSquares = function(nums) { let left = 0 let right = nums.length - 1 let len = nums.length - 1 let newArr = [] while(left <= right){ let num1 = nums[left]*nums[left] let num2 = nums[right]*nums[right] if(num1 > num2) { newArr[len--] = num1 left++ }else{ newArr[len--] = num2 right-- } } return newArr }
-
此时的时间复杂度为O(n),相对于暴力排序的解法O(n + nlog n)还是提升不少的
长度最小的子数组
-
这是一道滑动窗口的题目 ,虽然之前做过的,但还是忘了 ,基本上还是用暴力方法做出来的TT,而且判断了很多的边界条件,还不如直接俩for便利了 诶,不过 我想到的是要先确定好结束的位置 往前找, 可能是脑子里还有之前一点模糊的滑动窗口的印象。
-
var minSubArrayLen = function(target, nums) { if(nums[0] >= target) return 1 let len = nums.length - 1 let max = Infinity while(len >= 0){ let sum = 0 let index = 1 let next = len while(next >= 0){ sum = sum + nums[next] if(sum>=target){ max = Math.min(max,index) break } index++ next-- } len-- } if(max === Infinity) return 0 return max };
很难受!!!
-
滑动窗口解法
-
先来看一下代码
-
let left = 0 let right = 0 let min = Infinity let sum = 0 while(right < nums.length) { sum += nums[right] while(sum >=target){ min = Math.min(min,right - left + 1) sum -= nums[left] left++ } right++ } return min == Infinity? 0 : min
-
暴力循环中,通过双循环 ,一个确定开始位置 一个确定结束位置,这个距离其实就是窗口,滑动窗口。
窗口的起始位置如何移动:如果当前窗口的值大于target了,窗口就要向前移动 ,left就要加
窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。
动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)暴力解法降为O(n)。
-
为什么是On 我看了一下解释:
不要以为for里放一个while就以为是O(n^2)啊, 主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。
-
扩展练习leetcode.cn/problems/mi…76.最小覆盖子串
思路是一样的活动窗口。
-
var minWindow = function(s, t) { let len1 = s.length let len2 = t.length let map = new Map() for(let i = 0 ; i < len2 ; i++){ let str = t[i] map.set(str,(map.get(str)||0) + 1) } let maplen = map.size let res = '' let min = Infinity let left = 0 , right = 0 while(right < len1) { let str = s[right] if(map.has(str)){ map.set(str,map.get(str) - 1) } if(map.get(str) == 0) maplen-- while(maplen == 0) { let str2 = s[left] if(min > right - left +1){ min = right - left + 1 res = s.slice(left,right+1) } if(map.has(str2)){ map.set(str2,map.get(str2)+1) if(map.get(str2) == 1) maplen++ } left++ } right++ } return res };
-
螺旋矩阵2
-
这题直接做出来了,在纸上比比划划之后 ,也可能是之前做过的原因。这道题类似于模拟 ,就是在画圈 ,然后循环递减下去就可以了. emm 个人觉得比随想录里的算法容易理解一点。
-
其实就是四条边 上—右—下—左的顺序,然后每画完一条边,更新他的索引,因为你是从外圈往内圈画,肯定是越来越小的,废话不多说 一看代码 直接就懂!!
-
var generateMatrix = function(n) { let matrix = new Array(n).fill(0).map(item => new Array(0)) let num = 1 let left = 0 ,top = 0 let right = n - 1, bottom = n - 1 while(left <= right && top<=bottom) { for(let i = left ; i <= right ; i++) { matrix[top][i] = num num++ } top++ for(let i = top; i <= bottom ; i++){ matrix[i][right] = num num++ } right-- for(let i = right; i >=left ; i--){ matrix[bottom][i] = num num++ } bottom-- for(let i = bottom ; i>=top ; i--){ matrix[i][left] =num num++ } left++ } return matrix };
-
相似题型:螺旋矩阵leetcode.cn/problems/sp…
稍加修改!
-
var spiralOrder = function(matrix) { let sum = matrix[0].length * matrix.length let res = [] let top = 0, left = 0 let bottom = matrix.length - 1 let right = matrix[0].length - 1 while(left <= right && top<=bottom) { for(let i = left ; i <= right ; i++) { res.push(matrix[top][i]) } top++ for(let i = top; i <= bottom ; i++){ res.push(matrix[i][right]) } right-- for(let i = right; i >=left ; i--){ res.push( matrix[bottom][i]) } bottom-- for(let i = bottom ; i>=top ; i--){ res.push(matrix[i][left]) } left++ } return res.slice(0,sum) }
-