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
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. 四个内层循环 - 填充螺旋的每一边:
- 每个内层循环负责填充矩阵的一边。
- 从左到右:
for i in range(starty, n - offset):
- 从
(startx, starty)
开始,沿着顶部行向右填充,直到n - offset
列。
- 从上到下:
for i in range(startx, n - offset):
- 从顶部行的最右边,沿着右边列向下填充,直到
n - offset
行。
- 从右到左:
for i in range(n - offset, starty, -1):
- 从底部行的最右边,沿着底部行向左填充,直到
starty
列。
- 从下到上:
for i in range(n - offset, startx, -1):
- 从底部行的最左边,沿着左边列向上填充,直到
startx
行。
- 从左到右:
7.更新起始点:
startx += 1
和starty += 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)