算法学习 Day02 数组基础2

152 阅读3分钟

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层,每层遵循如下的迭代发方向进行遍历: image.png

  • 时间复杂度: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] 。

image.png

  • 时间复杂度:构造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]区间的和。