目录
算法详解
977.有序数组的平方
(一)遍历解法(暴力解法)
算法复杂度:遍历O(n) + 排序O(nlogn)
思路
(1)遍历每一个数组中的元素并执行平方操作;
(2)排序nums.sort()
。
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
length = len(nums)
for i in range(length): # 时间复杂度为O(n)
nums[i] = nums[i] ** 2
nums.sort() # 时间复杂度为O(nlogn)
return nums
(二)双指针解法
算法复杂度:O(n);
说明:while left <= right 将循环n次。
易错点
- 有序数组中可能含有负数。当负数出现时,其平方值可能远大于正数平方值。
- 仅包含正数的有序数组无需排列,因此即使采用遍历法算法复杂度为O(n)。
思路
- 当数组中存在负数时,数组的平方最大值出现在数组的“两端”。因此从两端同时遍历可以有效找到数组中平方的最大值。
代码
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
left, right, new_right = 0, len(nums) - 1, len(nums) - 1
new_nums = [0] * len(nums) # 生成一个和nums大小相同的数组
while left <= right:
if nums[left] ** 2 > nums[right] ** 2:
# 始终将比较之后的最大值添加到新数组中
new_nums[new_right] = nums[left] ** 2
# nums[left] ** 2 已经添加到新数组中故left右移
left += 1
else:
new_nums[new_right] = nums[right] ** 2
right -= 1
# 每对新数组赋值完一次之后移动一次新数组的下标
new_right -= 1
return new_nums
209. 长度最小的子数组
滑动窗口(小加右,大减左)
算法复杂度:O(n);
说明:while 将循环n次。
易错点
- 小加右:当前数字之和小于目标值时,增量为右指针的值。
- 大减左:当前数字之和大于(或等于)目标值时,减量为左指针的值。
- 注意:当数字之和满足目标值且循环没有结束时,依然需要往下继续寻找下一个满足需要的数组。
- 最小长度比较:当满足大于等于目标值时,可以通过
right-left+1
计算当前数组的长度,并与最小数组长度比较,保留最小长度。 - 注意:当大于目标值时虽然乍一看不满足条件,但大于目标值时数组长度一定也大于长度最小的数组,遂简化代码。
思路
- 初始化两个指针,按照“小加右,大减左”原则滑动窗口,满足条件的数组计算长度与最小长度(初始化为无穷大)比较。
代码
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
length = len(nums)
left, right = 0, 0
min_len = float('inf')
sum = 0
while right < length:
sum += nums[right] # 累加时新增的是右指针值
while sum >= target:
min_len = min(min_len, right-left+1) # 当大于目标值时长度一定大于最小长度
sum -= nums[left] # 超过/等于目标值时减掉左指针值
left += 1 # 执行完右移
right += 1 # (无论大于小于等于)执行完右移
return min_len if min_len != float('inf') else 0
59. 螺旋矩阵2
双循环算法
算法复杂度:O(n^2);
说明:内外for循环各O(n)。
易错点
- 循环不变量选取:如下图所示,每一圈螺旋的生成都按照类似的规律执行。其中螺旋数
loop = n // 2
。
- 奇数螺旋矩阵中心点值另外赋值:当n为奇数时,会出现最内圈螺旋只有一个值的现象,为和n为偶数的算法统一,且简化代码,另外赋值
nums[mid][mid]
,其中mid = n // 2
。
思路
- 初始化两个指针,按照“小加右,大减左”原则滑动窗口,满足条件的数组计算长度与最小长度(初始化为无穷大)比较。
代码
(1)内循环:可以首先根据上图(i,j)变化规律推导出每一圈螺旋变化的规律,代码如下:
cnt = 1
matrix = [[0]*n for _ in range(n)]
# i = 1
for j in range(n-1):
matrix[i][j] = cnt
cnt += 1
# j = n - 1
for i in range(n-1):
matrix[i][j] = cnt
cnt += 1
# i = n - 1
for j in range(n-1,2,-1):
matrix[i][j] = cnt
cnt += 1
# j = 1
for i in range(n-1,2,-1):
matrix[i][j] = cnt
cnt += 1
(2)外循环:offset是由循环不变量得到的变量值,即第一圈时,需要保留最后一个值最为下一圈的起始位置;第二圈时offset其实也为1,但是考虑到第一圈已经生成位置不需要再访问,因此offset为2,以此类推。注意:offset取值不能大于(小于等于)loop。总体代码如下:
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
cnt = 1
start_x = 0
start_y = 0
offset = 1
loop, mid = n // 2, n // 2
matrix = [[0]*n for _ in range(n)]
for offset in range(1, loop + 1):
for j in range(start_y, n-offset):
matrix[start_x][j] = cnt
cnt += 1
for i in range(start_x, n-offset):
matrix[i][n-offset] = cnt
cnt += 1
for j in range(n-offset, start_y, -1):
matrix[n-offset][j] = cnt
cnt += 1
for i in range(n-offset, start_x, -1):
matrix[i][start_y] = cnt
cnt += 1
start_x += 1
start_y += 1
# n为奇数时还需要填充一个芯
if n % 2 != 0:
matrix[mid][mid] = cnt
return matrix
总结
解决数组算法题记住“双指针”法。