Day02 代码随想录刷题
知识点:双指针、滑动窗口、模拟
一、LeetCode977.有序数组的平方
1.解题思路
考点为双指针,据题意原数组nums是一个非递减、可能带负数的整数数组,所以每个元素平方后最大值肯定出现在数组两边,不是左边就是右边。
2.代码实现
我们通过双指针从两头向里搜索,找到平方后值最大的元素,再将该值存入新建的列表res中去(从后往前排)。
根据输入数组的长度
len(nums)新建列表res,设计索引i,从后向前储存,实现res列表内元素的从小到大排列列表两头元素
nums[left]和nums[right]平方后的值大小判断可以通过两者相加实现,相加后为正,则右侧元素平方后值更大;否则左侧的负数平方后值更大。
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
# 双指针初始化
left, right = 0, len(nums) - 1
# 新建列表,内容初始化为 -1
res = [-1]*len(nums)
i = len(nums) - 1
while left <= right:
if nums[left] + nums[right] > 0:
res[i] = nums[right]**2
right -= 1
else:
res[i] = nums[left]**2
left += 1
i -= 1
return res
该解法相当于遍历了一遍数组nums,时间复杂度为O(n),因为额外还维护了一个长度为n的结果数组res,所以空间复杂度也为O(n)。
二、LeetCode209.长度最小的子数组
1.解题思路
考点为双指针实现滑动窗口,据题意可创建窗口右侧向右扩充,当窗口内元素满足要求后,窗口左侧开始向右收缩,期间找到满足要求的最小窗口长度min_len。当左侧窗口收缩导致窗口内元素不满足要求时,窗口会继续向右侧扩充,扩充与收缩依次循环,直至窗口右侧遍历完整个列表元素。
实质:
窗口不达标,右侧扩充;
窗口达标了,左侧收缩;
上述2条不断循环,期间保存最小窗口的长度,窗口右侧遍历完列表时结束循环
2.代码实现
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
left = right = 0 # 初始化窗口左右侧
window_sum = 0
min_len = float("inf") # 窗口长度初始为无穷大
while right < len(nums): # 设置循环中止条件
window_sum += nums[right]
while window_sum >= target: # 窗口达标
min_len = min(min_len, right - left + 1)
window_sum -= nums[left]
left += 1# 窗口左缩进
right += 1# 窗口不达标,窗口右扩充
if min_len == float("inf"):
return 0
else:
return min_len
该解法额外设计了left和right两个指针,数组每个元素最多被操作2次,总共时间复杂度是2n,所以时间复杂度是O(n),因为额外维护了2个指针,空间复杂度是O(1)。
三、LeetCode059.螺旋矩阵II
1.解题思路
考点为模拟,螺旋问题有规律,确定边界后用循环实现。循环需要找到循环不变量,即每次循环填充一圈,一圈有四边。最外层的边界索引为0到n-1,我们每边只填充索引为0到n-2的位置即可实现每次边填充规律都一样。
填充数组时还有规律:
假设循环填充多圈,每循环
i圈(i从0开始)后,每圈边界的填充索引开始点+i,终止点-i每轮循环向右、向下填充的索引一样,只是横行列不同;向左,向上类似
向右填充时,行不变,行是上边界
0,每循环i轮+i;列变化,索引由0到n-1,每轮循环开始点+i,终止点-i向下填充时,列不变,列是右边界
n-1,每循环i轮-i;行变化,索引由0到n-1,每轮循环开始点+i,终止点-i向左填充时,行不变,行是下边界
n-1,每循环i轮-i;列变化,索引由n-1到0,每轮循环开始点-i,终止点+i向上填充时,列不变,列是左边界
0,每循环i轮+i;行变化,索引由n-1到0,每轮循环开始点-i,终止点+i输入
n为奇数时,矩阵存在中心点,该值也需要补充
2.代码实现
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
# 确定循环圈数
loop = n//2
# 初始化结果矩阵:n*n的零矩阵
res = [[0]*n for _ in range(n)]
# 递增数num
num = 1
for i in range(0,loop):
# i是循环轮数,a是每次边填充的索引
for a in range(i,n - 1 - i):
res[i][a] = num
num += 1
for a in range(i,n - 1 - i):
res[a][n - 1 - i] = num
num += 1
for a in range(n - 1 - i, i, -1):
res[n - 1 - i][a] = num
num += 1
for a in range(n - 1 - i, i, -1):
res[a][i] = num
num += 1
# 奇偶判断是否需要补充中心值
if n%2 == 1:
res[loop][loop] = num
return res
该解法模拟矩阵大小为n*n且需要全部遍历填充,所以时间复杂度是O(n^2),此外还额外维护这个大小为n*n的矩阵,所以空间复杂度为O(n^2)。
文章介绍了使用双指针解决LeetCode中的三个问题:有序数组的平方、长度最小的子数组和螺旋矩阵II。通过双指针和滑动窗口策略,分别实现了在不同场景下的高效算法,时间复杂度均为O(n)。
921





