LC打怪录day2-数组(2) 有序数组的平方

977. 有序数组的平方

Given an integer array nums sorted in non-decreasing order, return an array of the squares of each number sorted in non-decreasing order.

Example 1:

Input: nums = [-4,-1,0,3,10]
Output: [0,1,9,16,100]
Explanation: After squaring, the array becomes [16,1,0,9,100].
After sorting, it becomes [0,1,9,16,100].

解读:

想象一下,你的数字排在一条直线上,最小的在左边,最大的在右边。现在,我们要做的是找到这些数字平方后最大的那个。

因为数字有正有负,所以最大的平方数可能在最左边(一个很小的负数平方后会变得很大),也可能在最右边(一个正数平方后也会变得很大)。这段代码就像是两个人在这条直线的两端开始找:一个从左边开始,一个从右边开始,他们各自检查自己这边的数字。

每次比较,两个人都会选出自己这边现在最大的数字,然后把它平方后放在一个新的排列里。因为我们要得到的是一个顺序排列,所以我们从新排列的最后面开始放,也就是说,最大的数放在最后面。

解题:

双指针
class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        l, r, i = 0, len(nums)-1, len(nums)-1 左指针,右指针,数组索引
        # 结果数组的写入位置的指针,逆序写入
        p = n - 1
        res = [float('inf')] * len(nums) #res是一个与输入列表num长度相同的数组,用来存放最后的结果
        执行双指针合并有序数组的逻辑
        # 由于逆序写入,绝对值大的先写入,并且指针移动
        while l <= r: #当左指针l小于等于右指针r时,循环继续
            if nums[l] ** 2 < nums[r] ** 2: # 左右边界进行对比,找出最大值
                res[i] = nums[r] ** 2 
如果右指针r位置的数字平方大,就将这个平方数放到结果数组res的i位置,然后右指针r向左移动一位。
                r -= 1 # 右指针往左移动
            else: 
如果左指针l位置的数字平方大或者相等,就将这个平方数放到结果数组res的i位置,然后左指针l向右移动一位。
                res[i] = nums[l] ** 2
                l += 1 # 左指针往右移动 
            i -= 1 # 存放结果的指针需要往前平移一位,这是为了在结果数组中从后往前填充数字。
        return res
(版本二)暴力排序法
class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        for i in range(len(nums)):
            nums[i] *= nums[i]
        nums.sort()
        return nums

209.长度最小的子数组 
Minimum Size Subarray Sum

Given an array of positive integers nums and a positive integer target, return the minimal length of a subarray whose sum is greater than or equal to target. If there is no such subarray, return 0 instead.

Example 1:

Input: target = 7, nums = [2,3,1,2,4,3]
Output: 2
Explanation: The subarray [4,3] has the minimal length under the problem constraint.

解读:

给定一个含有 n 个正整数的数组和一个正整数 target ,找出该数组中满足其和 ≥ target 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
示例:
输入:target = 7, nums = [2,3,1,2,4,3] 输出:2 解释:子数组 [4,3] 是该条件下的长度最小的子数组

目的是要解决一个与数字列表相关的问题。具体来说,它寻找列表中最短的连续子数组,使得这个子数组中的数字加起来至少等于一个特定的数值(称为“目标”)。如果存在多个这样的子数组,返回其中最短的一个的长度。如果不存在这样的子数组,则返回0。

假设我们有一些糖果,它们排成一行,每个糖果都有自己的重量。现在我们要找到一段连续的糖果,使得这些糖果的总重量至少是我们事先设定的一个目标值。我们希望这段连续的糖果尽可能短,这样我们就不用拿太多。

滑动窗口

暴力解法使用两个for循环

滑动窗口只用一个for循环,那么这个循环的索引,一定是表示 滑动窗口的终止位置。

滑窗为可伸缩的窗口,它可以覆盖列表中的一部分元素。这个窗口的大小就是子数组的长度,我们想要这个窗口尽可能的小。

class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        start = 0 #滑动窗口的起始位置
        end = 1 #滑动窗口的结束位置
        Sum = 0 #滑动窗口内元素的当前总和
        size = float("inf") #初始化size,这是一个非常大的数
        while end <= len(nums): #这个while循环会持续运行直到end超过了nums列表的长度
            Sum += nums[end-1] #不断将滑动窗口的下一个元素添加到Sum中
            while Sum >= target: #如果当前Sum达到或超过了target,我们进入另一个while循环,这个循环会不断尝试缩小窗口的大小(即减少start和end之间的距离),直到Sum小于target。
                size = min(size, end - start) #更新size为当前子数组的长度(如果它小于已记录的size)。
                Sum -= nums[start] #从Sum中减去滑动窗口起始位置的元素。
                start += 1 #将滑动窗口的起始位置向右移动,因为我们正在寻找更小的子数组。
            end += 1 #扩大滑动窗口的结束位置。
        return 0 if size == float("inf") else size

59.螺旋矩阵II

Spiral Matrix II

Given a positive integer n, generate an n x n matrix filled with elements from 1 to n2 in spiral order.

Input: n = 3
Output: [[1,2,3],[8,9,4],[7,6,5]]

这里一圈下来,我们要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来。

1. 初始化矩阵
  • 我们首先创建一个 n x n 的矩阵,初始时,所有的元素都设置为 0。
  • 例如,如果 n = 3,那么初始的矩阵是这样的:
    [0, 0, 0]
    [0, 0, 0]
    [0, 0, 0]
    2. 定义起始点和螺旋的层数
  • 我们从矩阵的左上角开始填充,这个点我们称为起始点(startx, starty),初始时它在矩阵的左上角。
  • 螺旋的层数 loop 是 n 除以 2,因为螺旋是层层向内缩进的。
  • 如果 n 是奇数,矩阵的中心点 mid 是 n 除以 2 的结果。
            startx, starty = 0,0
            loop, mid = n//2, n//2
3. 填充矩阵
  • 我们使用一个计数器 count,从 1 开始,用来填充矩阵。
  • 然后我们开始按层填充矩阵。每一层都是一个小的螺旋。
    • 我们先从左到右填充上面一行。
    • 然后从上到下填充右边一列。
    • 接着从右到左填充下面一行。
    • 最后从下到上填充左边一列。
  • 每填充完一层,起始点就向内移动一格,为下一层的填充做准备。​​​​​​​​​​​​​​​​​​​​​

4. 处理奇数情况

  • 如果 n 是奇数,中心点不会在上面的步骤中被填充。所以我们需要单独给中心点赋值。
 count = 1      # 计数:用来填充矩阵的当前数,从1开始

用比喻来说,就像是我们在画一个旋转的楼梯,从外面一圈圈向里画,每一圈都是一层楼梯,直到画到最中间的那一点。

5. 外层循环 - 控制层数
  • for offset in range(1, loop + 1):
  • 这个循环控制我们要填充的螺旋层数。offset 表示当前层数的偏移量,从1开始到loop(包含loop)。每一层实际上是矩阵的一圈。

6. 四个内层循环 - 填充螺旋的每一边

  • 每个内层循环负责填充矩阵的一边。
    1. 从左到右
      • for i in range(starty, n - offset):
      • (startx, starty)开始,沿着顶部行向右填充,直到n - offset列。
    2. 从上到下
      • for i in range(startx, n - offset):
      • 从顶部行的最右边,沿着右边列向下填充,直到n - offset行。
    3. 从右到左
      • for i in range(n - offset, starty, -1):
      • 从底部行的最右边,沿着底部行向左填充,直到starty列。
    4. 从下到上
      • for i in range(n - offset, startx, -1):
      • 从底部行的最左边,沿着左边列向上填充,直到startx行。

7.更新起始点

  • startx += 1starty += 1
  • 完成一圈螺旋之后,我们需要将起始点向内移动一格,以便开始下一圈的填充。​​​​​​​

​​​​​​​​​​​​​​8. 处理奇数情况 - 填充中心点

  • if n % 2 != 0: nums[mid][mid] = count​​​​​​​
  • 如果n是奇数,中间的点在上述循环中不会被处理。所以我们需要特别地填充这个中心点。
class Solution:
    def generateMatrix(self, n: int) -> List[List[int]]:
        nums = [[0] * n for _ in range(n)] #创建一个n x n的二维列表(矩阵)nums,所有元素初始值为0
        startx, starty = 0, 0               # 起始点:从矩阵的左上角开始填充
        loop, mid = n // 2, n // 2          # loop是螺旋的层数,迭代次数怕;mid是矩阵的中心点位置,仅当n为奇数时才会使用,矩阵的中心点
        count = 1                           # 计数:用来填充矩阵的当前数,从1开始

        for offset in range(1, loop + 1) :      #外层循环:用来控制填充的层数 每循环一层偏移量加1,偏移量从1开始
            for i in range(starty, n - offset) :    # 从左至右,左闭右开
                nums[startx][i] = count
                count += 1
            for i in range(startx, n - offset) :    # 从上至下
                nums[i][n - offset] = count
                count += 1
            for i in range(n - offset, starty, -1) : # 从右至左
                nums[n - offset][i] = count
                count += 1
            for i in range(n - offset, startx, -1) : # 从下至上
                nums[i][starty] = count
                count += 1                
            startx += 1         # 更新起始点
            starty += 1

        if n % 2 != 0 :			# 如果n是奇数,最后矩阵的中心点会被漏掉,因此需要单独填充;n为奇数时,填充中心点
            nums[mid][mid] = count 
        return nums

时间复杂度是O(n^2)

空间复杂度也是O(n^2)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值