任务
977. 有序数组的平方
给你一个按非递减顺序排序的整数数组 nums,返回每个数字的平方组成的新数组,要求也按非递减顺序排序。
思路
由于平方后最大值只可能出现在左右两边,所以每次取左右两边的较大值加入到新数组的尾部。故采用双指针法,一个指向尾部,一个指向头部,每次取符合条件的元素,放入到新数组中,注意循环条件,两个指针相遇时也需要处理当前位置的值,也就是最后一个未处理的值。(第一次做的时候妄图用同一个数组双指针遍历一次来处理,编码后发现后指针除了指示已完成的位置,还要保存该位置当前的数的平方,也就是说在迭代中的每一步,无法满足两个要求,所以需要新数组作为返回,后指针的作用和前指针一样,只是为了保存待放入的值。对比而言,之所以就地逆置可以在一个数组中完成,时因为在迭代中的每一步可以完成两个位置的确认,且此后也再也不需要这两个位置的信息了)
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
size = len(nums)
i = 0
j = size-1
resultList = []
while i<=j:
v0 = nums[i] * nums[i]
v1 = nums[j] * nums[j]
if v0 < v1:
resultList.insert(0,v1)
j-=1
else:
resultList.insert(0,v0)
i+=1
return resultList
209. 长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 target。
找出该数组中满足其总和大于等于 target 的长度最小的
子数组[numsl, numsl+1, ..., numsr-1, numsr],并返回其长度。如果不存在符合条件的子数组返回0
思路
两个指针遍历数组,其中一个表示以当前位置开头,另一个表示以当前位置结尾。两重循环,确认每个位置的最小长度。
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
size = len(nums)
result = 100000
i = 0
j = 0
while i < size:
sum = 0
subCount = 0
for j in range(i,size):
sum += nums[j]
subCount += 1
if sum >= target:
result = subCount if subCount<result else result
break
i+=1
result = 0 if result==100000 else result
return result
滑动窗口法:这种方法比较难想到,与上面暴力法相反的,不是确定每个位置开头的满足条件子数组,而是确定每个位置结尾的满足条件子数组,再把头往后移,最终找到每个位置满足条件的最小子数组。需要注意的是count不是累加,是可以直接得到的,即j-i+1。
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
size = len(nums)
result = float('inf')
i = 0
j = 0
sum = 0
subCount = 0
while j <size:
sum += nums[j]
while sum >= target:
subCount = j - i + 1
result = subCount if subCount < result else result
sum -= nums[i]
i += 1
j+=1
result = 0 if result==float('inf') else result
return result
59. 螺旋矩阵 II
给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
思路:
模拟类题目,需要弄清楚边界。先想到外圈是简单的模拟,后续需要想到实际每一轮(不断向内圈)都是不断的旋转,按照向右向下向左向上的方式,一圈一圈的旋转,最简单的循环终止条件就是当值等于n平方时。
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
result = [[0] * n for _ in range(n)]
num = 1
left,right,top,bottom = 0,n,0,n
endNum = n * n
while(num <= endNum):
for j in range(left,right):
result[top][j] = num
num += 1
top += 1
for i in range(top,bottom):
result[i][right-1] = num
num+=1
right-=1
for j in range(right-1,left-1,-1):
result[bottom-1][j] = num
num+=1
bottom-=1
for i in range(bottom-1,top-1,-1):
result[i][left] = num
num+=1
left+=1
return result
总结
数组部分的内容主要如下
- 二分查找 失败返回-1和失败返回查找位置,看似两个非常相近的问题,实际解决思路确实非常不同,一个是缩小查找范围,另一个是将数组从全员未知变成左右边两个特征的分段
- 双指针法,有时是快慢指针法,之前的day1的移除元素题目 slow是负责维护满足条件的元素的哨兵,fast是负责检查每个元素。而有序数组的平方这道题目,并不是快慢指针,由于满足条件的一定在数组两端,实际上只是比较两个前后两个指针所指向的值的大小,它们的功能相同均是检查指向元素。
- 滑动窗口法 由通常想到的确定每个开始位置的子数组改为了每个结束位置的满足条件的子数组,再移动头的思路。
- 模拟类 需要抓住循环条件和边界条件,如螺旋矩阵 II