Content
题目一:977. 有序数组的平方
题目描述
个人觉得题目描述有些问题“非递减顺序”不太严谨,[4, 5, 4, 7, 9, 2]也是非递减序列。猜测题目想表达“递增序列”。
解题思路
简单想法:双指针从左右端分别算平方数,哪个大则添加入新列表,依次遍历即可,最后返回逆序新列表。
时间复杂度:O(n)
空间复杂度:O(n)
代码
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
square_list = []
left, right = 0, len(nums) - 1
while left <= right:
if nums[left] * nums[left] < nums[right] * nums[right]:
square_list.append(nums[right] * nums[right])
right -= 1
else:
square_list.append(nums[left] * nums[left])
left += 1
return square_list[::-1]
题目二:209. 长度最小的子数组
1. 题目描述
2. 解题思路
暴力破解法(Can’t AC,超时),原因在于对于数组过长(目测元素数量10000+),并且很多种连续元素求和能满足目标条件
这里重点归纳双指针“滑动窗口”方法。
方法:
left, right = 0
min_len = len(nums)
total_sum = 0 # 左指针和右指针之间元素求和
for right in range(0, len(nums)):
total_sum += nums[right]
while total_sum >= target:
left
左指针和右指针之间元素求和记为sum
(以下描述sum
会根据左右指针变动自动更新值),右指针控制结束位置,左指针控制开始位置,左右指针初始化均为0
.
- 当
sum
小于目标值时,一直动右指针 - 当
sum
大于等于目标值时,左指针右移并记录最短长度 - 右指针右移直至数组最后一个位置
优点:
- 最直观优点为减少了暴力解法中重复的求和操作
- 虽然也是两层循环(
for+while
),其中外层for
控制右指针,内层while
循环控制左指针,但是每次执行循环(不论是内循环还是外循环)左右指针必有一个指针在动,这样最多左右指针同时移动到末尾(即[1, 1, 1, 1, 100]
,101
这种输入情况), 因此时间复杂度为O(2*n)
- 右指针的作用即增加新元素,左指针的作用为及时剔除掉没有用的元素
3. 代码
3.1 暴力解法
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
min_len = len(nums) + 1
for i in range(len(nums)):
total_sum = 0
this_len = 0
for j in range(i, len(nums)):
total_sum += nums[j]
this_len += 1
if total_sum >= target and this_len < min_len:
min_len = this_len
break
if total_sum < target:
if min_len == len(nums) + 1:
return 0
else:
return min_len
if min_len == len(nums) + 1:
return 0
else:
return min_len
3.2 左右指针滑动窗口法
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
min_len = len(nums)
this_len = 0
left, right = 0, 0
total_sum = 0
for right in range(len(nums)):
total_sum += nums[right]
this_len += 1
while total_sum >= target:
total_sum -= nums[left]
left += 1
this_len -= 1
min_len = min(this_len, min_len)
# 不符合条件时min_len == len(nums)恒成立
if min_len == len(nums):
return 0
# 符合条件时min_len < len(nums)恒成立
else:
return min_len + 1
题目三:59. 螺旋矩阵II
题目描述
解题思路
开始想的太复杂了,其实很多if
/else
条件根本用不到(例如往右走到头根本不用考虑往上走的情况即不用考虑row_direction=-1
的情况,此时row_direction=1
恒成立,类似不存在情况还有很多),实际上row_direction
和column_direction
只需其中一个即可。
本题解法的关键在于弄明白if
/else
的判断条件:
- 前提条件:往上下左右走的条件均为下一个位置不为空且下一个位置不到边界
- 由顺时针决定了以下两点
- 如果之前往右走,则走到头一定往下走
- 如果之前往左走,走到头一定往上走
- 往上或者下走到头则左右方向颠倒
代码
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
init_num = 0
row = 0
column = 0
this_num = 1
column_direction = 1
result = [[init_num] * n for i in range(n)]
while this_num != n * n:
result[row][column] = this_num
this_num += 1
if column_direction == 1:
if column != n - 1 and result[row][column + 1] == init_num:
column += 1
else:
if row != n - 1 and result[row + 1][column] == init_num:
row += 1
else:
column_direction = -1
column -= 1
else:
if column != 0 and result[row][column - 1] == init_num:
column -= 1
else:
if row != 0 and result[row - 1][column] == init_num:
row -= 1
else:
column_direction = 1
column += 1
result[row][column] = n * n
return result