977.有序数组的平方
题目建议: 本题关键在于理解双指针思想
题目链接:. - 力扣(LeetCode)
文章讲解:代码随想录
第一想法
暴力排序
一开始先用for循环,再用归并排序,发现超时了
然后直接用python自带的快速排序
def sortedSquares(self, nums: List[int]) -> List[int]:
return sorted(num * num for num in nums)
复杂度 O(nlogn)
推荐算法
双指针法
核心思想:负数数组平方之后可能变成最大值,只能在数组的两边,不会在中间。因此使用双指针比较左右两个数的大小。
def sortedSquares(self, nums: List[int]) -> List[int]:
left, k, right = 0, len(nums)-1, len(nums)-1
res = [float('inf')] * len(nums)
while k >= 0:
if nums[right] ** 2 >= nums[left] ** 2:
res[k] = nums[right] ** 2
right -= 1
k -= 1
else:
res[k] = nums[left] ** 2
left += 1
k -= 1
return res
209.长度最小的子数组
题目建议:本题关键在于理解滑动窗口思想
题目链接:. - 力扣(LeetCode)
文章讲解:代码随想录
自己看到题目的第一想法
之前接触过类似题目,因此选择滑动窗口来做
debug过程中发现几个错误点:
1. 第一重while循环边界条件,不需要left < length, 仅需要right<length即可
2. 第二重判断cur_sum与目标值的大小,需要用一个while循环来不断地减去left指针的数字
3. min_len 初始设置需要设置为float('inf'),我一开始设置为0,导致每次min操作都得到0
4. 返回值时,如果min_len初始值没有被改变,则直接返回0
看完代码随想录之后的想法
想法是一样的,但是我自己具体代码实现过程问题比较大,参考代码随想录修改了自己的代码
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
left,right=0,0
cur_sum = 0
min_len = float('inf')
length = len(nums)
while right < length:
cur_sum += nums[right]
while cur_sum >= target:
min_len = min(min_len,right-left+1)
cur_sum -= nums[left]
left += 1
right += 1
return min_len if min_len != float('inf') else 0
59.螺旋矩阵II
题目建议: 本题关键还是在转圈的逻辑,在二分搜索中提到的区间定义,在这里又用上了。
题目链接:. - 力扣(LeetCode)
文章讲解:代码随想录
自己看到题目的第一想法
创建两个数组,一个用来赋值,一个用来标记是否访问过
按照右,下,左,上的顺序依次赋值,两层while循环嵌套
def generateMatrix(self, n: int) -> List[List[int]]:
nums = [[1]*n for i in range(n)]
label = [[0] * n for i in range(n)]
cur_num = 1
i = 0
j = 0
nums[i][j] = cur_num
label[i][j] = 1
while cur_num <= n**2:
while ((j + 1) < n and label[i][j+1] == 0):
j += 1
cur_num += 1
nums[i][j] = cur_num
label[i][j] = 1
while ((i+1) < n and label[i+1][j] == 0):
i += 1
cur_num += 1
nums[i][j] = cur_num
label[i][j] = 1
while ((j-1) >= 0 and label[i][j-1] == 0):
j -= 1
cur_num += 1
nums[i][j] = cur_num
label[i][j] = 1
while ((i-1) >= 0 and label[i-1][j] == 0):
i -= 1
cur_num += 1
label[i][j] = 1
nums[i][j] = cur_num
if cur_num == n**2:
break
return nums
看完代码随想录之后的想法
代码随想录中使用了二分法的原则, 而我的代码是使用了边界判断和label判断,空间复杂度要高一些
使用二分法 坚持循环不变量的原则;画四条边,每条边都坚持左闭右开的原则;每条边走长度的一半。(这个想法很神奇,需要一点观察力);需要注意每次大循环后,x和y的起始点要+1
def generateMatrix(self, n: int) -> List[List[int]]:
nums = [[0] * n for _ in range(n)]
startx, starty = 0, 0
loop, mid = n//2, n//2
count = 1
for offset in range(1, loop+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, starty, -1): #从下到上
nums[i][starty] = count
count += 1
startx += 1 # 更新起始点 进入内层循环了
starty += 1
if n % 2 != 0: #当n为奇数时,填充中心点
nums[mid][mid] = count
return nums
但是这个代码的时间消耗和空间消耗都大于我自己写的代码
总结
主要练习了双指针,滑动窗口,二分法
文章链接:代码随想录