Day2 滑动窗口 长度最小的子数组 最小覆盖子串 螺旋矩阵问题!

70 阅读3分钟

刷题Day2

依然是数组类的题目!

有序数组的平方

  • leetcode.cn/problems/sq…

  • 一开始直接想到了暴力 平方然后排序,注意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)还是提升不少的

长度最小的子数组

  • leetcode.cn/problems/mi…

  • 这是一道滑动窗口的题目 ,虽然之前做过的,但还是忘了 ,基本上还是用暴力方法做出来的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
    };
    

image-20230302115104262

很难受!!!

  • 滑动窗口解法

    • 先来看一下代码

    •  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

  • leetcode.cn/problems/sp…

  • 这题直接做出来了,在纸上比比划划之后 ,也可能是之前做过的原因。这道题类似于模拟 ,就是在画圈 ,然后循环递减下去就可以了. 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)
      }