代码随想录算法训练营第二天(数组篇)|Leetcode209长度最小的子数组,Leetcode59螺旋矩阵II,代码随想录区间和,代码随想录开发商购买土地
Leetcode 209 长度最小的子数组
题目链接: 长度最小的子数组
思路: 题目给定一个数组,要求找出数组中满足区间内元素和大于等于给定值的连续区间的最小长度,若不存在满足条件的区间,则返回0。
本题可以通过维护一个滑动窗口解决,通过维护快慢指针,我们可以框定一块区间。
快指针的移动逻辑为: 遍历整个数组,不断将数组中的下一个元素加入到当前区间里;
而慢指针的移动逻辑为: 当区间和减去慢指针所指向的元素后,仍然大于等于给定值时,则说明当前慢指针指向的元素可以删去,此时将慢指针向前移动。重复此操作直到慢指针无法继续前移为止。
代码具体实现
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
leftIdx = 0
sum = 0
minLen = len(nums) + 1
for rightIdx in range(len(nums)):
sum += nums[rightIdx]
if sum >= target: # 当找到满足条件的区间时,更新区间的长度
minLen = min(minLen, rightIdx - leftIdx + 1)
while sum - nums[leftIdx] >= target: # 此处用while而不是if,不断前移慢指针,直到无法继续移动为止
sum -= nums[leftIdx]
leftIdx += 1
minLen = min(minLen, rightIdx - leftIdx + 1)
return minLen if minLen != (len(nums) + 1) else 0
时间复杂度: O(n)
,因为仅遍历一次数组
Leetcode 59 螺旋矩阵II
题目链接: 螺旋矩阵II
思路: 本题需要按照螺旋顺序,打印出指定大小(n行n列,n由参数给出)的二维数组。
本题的重点在于循环不变量思想的实践。关于循环不变量的准确定义,可以查看维基百科的相应定义。本人对于循环不变量思想的粗浅理解为:其是你在进入循环前设定的一个“规则”,且这一规则在循环执行过程中始终没有被打破。
考虑n为奇数
和n为偶数
的两种情况: 假设n为奇数,则其存在一个"中心"需要额外处理;而当n为偶数时,则不存在相应中心。
再考虑如何按照螺旋顺序打印出每一层螺旋,假设n为3,此时期望打印出的数组为:
1 2 3
8 9 4
7 6 5
我们在设定循环的边界条件时,一定要按照预设的标准严格执行,以免出现重叠或者遗漏。如在本题中,考虑循环边界时,严格按照左闭右开区间进行处理。
最后,考虑待打印的螺旋数,观察得到,需要打印n//2
层螺旋,且当打印完成外层的螺旋后,处理内层的螺旋时,需要调整起始位置和终止位置
具体代码实现
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
startx, starty = 0, 0
mid = n // 2
loops = n // 2
offset = 1 # 偏移值,当每打印完一层螺旋后就加1,控制每一层的边界
count = 1
matrix = [[0] * n for _ in range(n)]
while loops:
# 上
for i in range(starty, n-offset):
matrix[startx][i] = count
count += 1
# 右
for i in range(startx, n-offset):
matrix[i][n-offset] = count
count += 1
# 下
for i in range(n-offset, starty, -1):
matrix[n-offset][i] = count
count += 1
# 左
for i in range(n-offset, startx, -1):
matrix[i][starty] = count
count += 1
startx += 1 # 打印完当前螺旋,更新循环的边界条件
starty += 1
offset += 1
loops -= 1
if n % 2 == 1: # 当n为奇数时,补全中心元素
matrix[mid][mid] = count
return matrix
区间和
题目链接: 区间和
给定一个数组,要求返回给定区间中所有元素的和。
输入描述: 第一行输入为整数数组 Array 的长度 n,接下来 n 行,每行一个整数,表示数组的元素。随后的输入为需要计算总和的区间,直至文件结束。
输出描述: 输出每个指定区间内元素的总和。
输入示例:
5
1
2
3
4
5
0 1
1 3
输出示例:
3
9
思路:
本题主要是引入了前缀和思想。试想给定一个数组nums=[1,3,2,5,6]
,要求区间0~2
和0~3
上的值。假设直接累加相应区间上元素的值,则进行了重复的计算。事实上,区间0~3
上元素的和可以由区间0~2
上元素的和加上nums[3]
得到。因此,我们不妨创建一个前缀和数组sum_array
,其中sum_array[i]
的含义为,从nums[0]
开始到nums[i]
区间内元素的和。通过前缀和数组,我们避免了重复的计算。
同时,本题采用ACM模式,不同于Leetcode的核心代码模式,ACM模式要求自行处理输入输出。
在python中,常用的处理输入的函数包括:
input()
: 读取一行的内容,自动去除换行符,读取大量数据时速率较慢
sys.stdin.readline()
: 直接从标准输入流读取一行内容,需要手动去除换行符,适合读取大量数据
具体代码实现:
import sys
def get_range_sum():
"""给出指定区间内元素的总和"""
array_len = int(input())
array = [0] * array_len
sum = 0
sum_array = [0] * array_len
for i in range(array_len):
array[i] = int(input())
sum += array[i]
sum_array[i] = sum
while True:
line = sys.stdin.readline()
if not line:
break
start_idx, end_idx = map(int, line.strip().split())
if start_idx == 0:
print(sum_array[end_idx])
else:
print(sum_array[end_idx] - sum_array[start_idx-1])
开发商购买土地
题目链接: 开发商购买土地
【输入描述】: 前两个正整数,代表 n 和 m。即接下来的 n 行,每行输出 m 个正整数。后续的元素为二维数组中的内容。
【输出描述】: 请输出一个整数,代表两个子区域内土地总价值之间的最小差距。
【输入示例】: 3 3 1 2 3 2 1 3 1 2 3
【输出示例】: 0
本题可以简单理解为给定一个二维数组,允许通过横向切割或者纵向切割将数组分为两个部分,使得两个部分元素总和的差值尽量小,并返回差值。
思路: 本题实际上可以转换为前缀和问题。由于给定的二维数组允许横向切割和纵向切割,需要分别讨论这两种情况进行分割时,各自切割方式得到的两个部分的最小差值,最终汇总得到结果。
具体代码实现:
import sys
sys_input = sys.stdin.readline
def buy_land():
data = list(map(int, sys_input().split()))
row, col = data[0], data[1]
sum = 0
matrix = [[0] * col for _ in range(row)]
idx = 2
for i in range(row):
for j in range(col):
matrix[i][j] = data[idx]
sum += data[idx] # 记录元素总和
idx += 1
horizontal_arr = [0] * row
for i in range(row):
for j in range(col):
horizontal_arr[i] += matrix[i][j] # 记录横向前缀和
vertical_arr = [0] * col
for j in range(col):
for i in range(row):
vertical_arr[j] += matrix[i][j] # 记录纵向前缀和
result = float('inf')
horizontal_cut = 0
for i in range(row):
horizontal_cut += horizontal_arr[i] # 尝试不同的横向切割方式,尝试找出两部分最小差值
result = min(result, abs(sum-horizontal_cut*2))
vertical_cut = 0
for j in range(col):
vertical_cut += vertical_arr[j] # 尝试不同的纵向切割方式
result = min(result, abs(sum-vertical_cut*2))
return result
时间复杂度: O(n^2)