209. 长度最小的子数组
题目:给定一个含有 n *个正整数的数组和一个正整数 target ,找出该数组中满足其总和大于等于 target的长度最小的子数组,[numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度 。 如果不存在符合条件的子数组,返回 0 。
解题思路
滑动窗口题目,使用left、right动态维护一个窗口,right扩张时找可行解,收缩时寻找最优解。具体的,sum<target时候right扩张,sum>target后收缩left,并且更新长度最小子数组的长度。
本题使用滑动窗口
- 时间复杂度:O(n)
- 空间复杂度:O(1)
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
# [left,right)是窗口的区间,计算数组和,长度为right-left
if not nums:
return 0
left, right = 0,0
min_len = float("inf")
window_sum = 0
while right < len(nums):
window_sum += nums[right]
right += 1
while window_sum >= target:
min_len = min(min_len, right - left) # 注意right已经+1了
window_sum -= nums[left]
left += 1
return min_len if min_len != float("inf") else 0
总结
需要注意下面的细节,容易遗漏:
1 输入为空时返回0
2 min_len设置一个较大值float("inf"),如果最后还是float("inf")说明无答案,需要返回0
3 right+=1的位置在收缩窗口之前,此时窗口范围是[left,right), 因此窗口长度为right-left。
59. 螺旋矩阵 II
题目:给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
解题思路
本题模拟顺时针遍历矩阵,边界条件较难处理。nxn的矩阵有n/2层,每层遵循如下的迭代发方向进行遍历:
- 时间复杂度:O(n^2)
- 空间复杂度:O(1)
class Solution:
def generateMatrix(self, n: int) -> [[int]]:
mat = [[0] * n for _ in range(n)]
target = n * n
left, right, top, bottom = 0, n-1, 0, n-1
val = 1
while val <= target:
# left to right
for j in range(left, right+1):
mat[top][j] = val
val += 1
top += 1
# top to bottom
for i in range(top, bottom+1):
mat[i][right] = val
val += 1
right -= 1
# right to left
for j in range(right, left-1, -1):
mat[bottom][j] = val
val += 1
bottom -= 1
# bottom to top
for i in range(bottom, top-1, -1):
mat[i][left] = val
val += 1
left += 1
return mat
总结
硬背吧,参考的这篇文章,过程比较清晰59. 螺旋矩阵 II(模拟,清晰图解)
58. 区间和(第九期模拟笔试)
题目:给定一个整数数组 Array,请计算该数组在每个指定区间内元素的总和。
解题思路
前缀和,preSum[i]记录从0到i的元素之和(长度为size+1),如果要计算[i,j]的区间之和,只需要算preSum[j+1]-preSum[i] 。
- 时间复杂度:构造preSum时O(n),计算[a,b]区间和时O(1)
- 空间复杂度:O(n)
import sys
ipt = sys.stdin.read().strip().splitlines()
size = int(ipt[0].strip())
vec = [int(ipt[i + 1].strip()) for i in range(size)]
range_ls = [line.strip().split() for line in ipt[size + 1:]]
preSum = [0] * (size + 1)
for i in range(1, size + 1):
preSum[i] = preSum[i - 1] + vec[i - 1]
for (a, b) in range_ls:
a, b = int(a), int(b)
val = preSum[b + 1] - preSum[a]
print(val)
总结
代码参考labuladong。 这道题使用前缀和的方法可以在O(1)的时间内计算任意区间的元素之和,非常高效。我们需要先构建前缀和数组preSum,然后根据公式preSum[b+1] - preSum[a]来计算[a,b]区间的和。