【刷题笔记】977有序数组的平方、209长度最小的子数组、59螺旋矩阵II、54螺旋矩阵

977有序数组的平方

题目链接:
https://leetcode.cn/problems/squares-of-a-sorted-array/
文章讲解:https://programmercarl.com/0977.%E6%9C%89%E5%BA%8F%E6%95%B0%E7%BB%84%E7%9A%84%E5%B9%B3%E6%96%B9.html
视频讲解:
https://www.bilibili.com/video/BV1QB4y1D7ep

思路

  • 虽然数组是非递减的,但是要考虑到数组的左半部分是负数的情况,比如数组是[-100,-50,0,10],非递减,但是平方之后,为[10000,2500,0,100],显然不是非递减的。因此我们不能从第一个数遍历到最后一个数,依次求平方,这种方法只适用于数组中的数字全部大于0的情况。
  • 假设数组是从负数过渡到正数,那么求平方后,最大的数应该出现在最左边或最右边。对于全为正数或全为负数的情况,可以看作它的一种特殊形式。
  • 因此我们选择用左右指针从两头向中间进行收缩,依次比对平方后的数值,满足要求就加入结果集。
  • 注意这里while中为什么是<=号,而不是<号?考虑一种极端情况,即全为负数的情况,当处理完倒数第二个数,left向后移动,此时left和right都指向了最后一个数,即left=right。如果此时退出循环,那么就会漏掉最后一个数。所以while中的条件是left<=right。
class Solution(object):
    def sortedSquares(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        ans = []
        n = len(nums)
        if n == 0:
            return nums

        left = 0
        right = n-1
        while(left <= right):
            left_num = nums[left] * nums[left]
            right_num = nums[right] * nums[right]
            if left_num >= right_num:
                ans.append(left_num)
                left += 1
            else:
                ans.append(right_num)
                right -= 1
        return ans[::-1]

209长度最小的子数组

题目链接:
https://leetcode.cn/problems/minimum-size-subarray-sum/
文章讲解:https://programmercarl.com/0209.%E9%95%BF%E5%BA%A6%E6%9C%80%E5%B0%8F%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84.html
视频讲解:
https://www.bilibili.com/video/BV1tZ4y1q7XE

思路

  • 因为题目说了是正整数的数组和正整数的target,那么当使用两个指针作为窗口的起始和结束时,右指针向前走,一定会使窗口中的元素和变大,左指针向前走,一定会使窗口中的元素和变小。
  • 因此,我们从位置0开始,每次让右指针向前走一位,如果窗口中的元素和小于target,那么右指针继续向前走。
  • 如果窗口中的元素和大于等于target,那么此时记录窗口的长度,然后左指针向前走,收缩窗口,记录窗口长度,收缩窗口......直到窗口中的元素和小于target。那么最终我们会得到一个全局最短的窗口长度。
  • 题目要求,如果没有满足要求的窗口,那么返回0。所以这里我对最小长度的初始化就是0,因为我们遍历中计算出的窗口长度最小也是1,即窗口中只有一个数。所以,如果我们能找到符合要求的窗口,窗口长度一定是大于等于1的。所以这里初始化为0没有问题。
class Solution(object):
    def minSubArrayLen(self, target, nums):
        """
        :type target: int
        :type nums: List[int]
        :rtype: int
        """
        n = len(nums)
        left = 0
        ans = 0 # 用于记录滑动窗口中的和
        minLen = 0 # 用于记录最小长度

        for right in range(0, n):
            ans += nums[right] # right向前走,更新窗口的和

            if ans < target: # 如果窗口的和小于target,那么right继续向前走
                continue

            # 如果窗口和大于target,此时left持续向前走,收缩窗口,并更新窗口长度
            while(ans >= target): 
                # right-left+1是窗口的长度
                minLen = min(right-left+1, minLen) if minLen != 0 else right-left+1
                # 窗口收缩
                ans -= nums[left] 
                left += 1 
        return minLen

59螺旋矩阵II

题目链接:
https://leetcode.cn/problems/spiral-matrix-ii/
文章讲解:https://programmercarl.com/0059.%E8%9E%BA%E6%97%8B%E7%9F%A9%E9%98%B5II.html
视频讲解:
https://www.bilibili.com/video/BV1SL4y1N7mV/

思路

  • 这里用的是螺旋矩阵的通用写法,注意填充的时候要有原则,以最外面一圈为例,填充第一行时,不填充最后一列的元素;填充最右列的时候,不填充最后一行的元素。四个方向都按照这个原则,就不会写乱。
  • while的条件为什么是top
  • 若n为偶数,以2x2的矩阵为例,四个方向打印一圈后,top=1,right=0,bottom=0,left=1,所以不管使用<还是<=,都会退出循环,是没有影响的。
  • 重点在于n为奇数的情况,以3x3的矩阵为例,四个方向打印一圈后,top=1,right=1,bottom=1,left=1,即,若n为奇数,剩中间一个空的时候,四个指针的数值一定是相同的,即在最中心的位置相遇。如果使用<号,此时不会继续循环,那么我们直接对最后一个空位置赋值即可;如果使用<=号,那么此时仍旧会进入循环,我们前面说过,比如填充第一行时,我们其实只对[left,right-1]的位置进行了填充,即[left,right)的左闭右开区间。那么当四个指针相遇时,左闭右开的区间其实已经没有意义了,就不需要再进入了。
class Solution(object):
    def generateMatrix(self, n):
        """
        :type n: int
        :rtype: List[List[int]]
        """
        if n == 0:
            return []
        maxtrix = [[0] * n for i in range(n)]

        top = 0
        right = n-1
        bottom = n-1
        left = 0
        count = 1

        while(top < bottom and left < right):
            for i in range(left, right):
                maxtrix[top][i] = count
                count += 1
            
            for j in range(top, bottom):
                maxtrix[j][right] = count
                count += 1

            for p in range(right, left, -1):
                maxtrix[bottom][p] = count
                count += 1

            for q in range(bottom, top, -1):
                maxtrix[q][left] = count
                count += 1

            # 一圈转完之后,再更新指针
            top += 1
            right -= 1
            bottom -= 1
            left += 1

        # 如果n为奇数,那么还剩中间一个位置需要填
        if n % 2 == 1:
            maxtrix[top][top] = count
        return maxtrix

54螺旋矩阵

思路

  • 这道题由于矩阵是mxn的,转圈时区间的定义稍有不同。目前也没有想到比较好的解释,后面再补充吧。
class Solution(object):
    def spiralOrder(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: List[int]
        """
        if len(matrix) == 0 or len(matrix[0]) == 0:
            return []

        m = len(matrix)
        n = len(matrix[0])
        ans = []

        top = 0
        right = n-1
        bottom = m-1
        left = 0

        while(top <= bottom and left <= right):
            for i in range(left, right+1):
                ans.append(matrix[top][i])
            top += 1
            
            for i in range(top, bottom+1):
                ans.append(matrix[i][right])
            right -= 1
            
            if top <= bottom:
                for i in range(right, left-1, -1):
                    ans.append(matrix[bottom][i])
                bottom -= 1

            if left <= right:
                for i in range(bottom, top-1, -1):
                    ans.append(matrix[i][left])
                left += 1

        return ans

你可能感兴趣的:(【刷题笔记】977有序数组的平方、209长度最小的子数组、59螺旋矩阵II、54螺旋矩阵)