209.长度最小的子数组
题目链接:209. 长度最小的子数组 - 力扣(LeetCode)
文章讲解:代码随想录
视频讲解:拿下滑动窗口! | LeetCode 209 长度最小的子数组_哔哩哔哩_bilibili
题目
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其总和大于等于 target 的长度最小的 子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
示例 2:
输入:target = 4, nums = [1,4,4] 输出:1
示例 3:
输入:target = 11, nums = [1,1,1,1,1,1,1,1] 输出:0
提示:
1 <= target <= 1091 <= nums.length <= 1051 <= nums[i] <= 104
进阶:
如果你已经实现 O(n) 时间复杂度的解法, 请尝试设计一个 O(n log(n)) 时间复杂度的解法。
暴力解法
两个指针指向起点和终点,两层循环,求两个位置中间的和,如果超过给的值就更新结果,然后和上一个结果比较谁的长度更小谁就是下一个结果。时间复杂度O(n^2),力扣警告超出时间限制。
from typing import List
# 力扣部分开始
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
rel=float('inf')#定义子序列长度为无穷大
sum=0#子序列之和
sumlen=0#子序列长度
for i in range(len(nums)):
sum=0
for j in range(i,len(nums)):#j可以=i到len(nums)-1,j=i时,子序列长度为1,自己不会和自己相加
sum+=nums[j]#子序列之和
sumlen=j-i+1#子序列长度
if sum>=target:#如果子序列之和大于等于目标值
rel=min(rel,sumlen)#更新子序列长度
break#跳出内层循环
return rel if rel!=float('inf') else 0#如果没有满足条件的子序列,返回0
# 力扣部分结束
# 测试代码
if __name__ == "__main__":
solution = Solution()
target = 7
nums = [2,3,1,2,4,3]
result = solution.minSubArrayLen(target, nums)
print(result) # 输出: 2
target1 = 2
nums = [1,1,1,1,1]
result = solution.minSubArrayLen(target1, nums)
print(result) # 输出: 2
滑动窗口
动态调节子序列初始位置和最终位置,得到结果
滑动窗口可以理解为双指针的一种
fast遍历整个数组,一个for循环
slow跟在后面,一边计算fast和slow之间的元素总和sum以及序列长度sumlen
在总和>目标的情况下,sum>=target,slow就移动,初始位置前移,子序列长度减小,求最小长度

sum+=nums[fast]#fast一边往前走一边把元素扔到sum中
while sum>=target:
sumlen=fast-slow+1#计算窗口长度
result=min(result,sumlen)#更新最小长度
sum-=nums[slow]#slow一边前移一边把前面的元素踢出sum,减小sum的长度以求出最小符合条件的
slow+=1
每个元素进入滑动窗口再出滑动窗口,被操作两次,2*n,时间复杂度为O(n)
不是循环套循环就是O(n^2),暴力解法两个for循环,一个i一个j,都遍历n个,i中每个j都会被操作n次,n个n所以是n*n,时间复杂度是O(n^2)
from typing import List
# 力扣部分开始
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
rel= float('inf') # 初始化结果为正无穷
sum=0
slow=0 # 滑动窗口的左边界
# 遍历数组,使用滑动窗口
for fast in range(len(nums)):
sum+=nums[fast] # 扩大窗口
while sum >= target:
rel = min(rel, fast - slow + 1)
sum -= nums[slow] # 缩小窗口
slow += 1
return rel if rel != float('inf') else 0
# 力扣部分结束
# 测试代码
if __name__ == "__main__":
solution = Solution()
target = 7
nums = [2,3,1,2,4,3]
result = solution.minSubArrayLen(target, nums)
print(result) # 输出: 2
target1 = 2
nums = [1,1,1,1,1]
result = solution.minSubArrayLen(target1, nums)
print(result) # 输出: 2
59.螺旋矩阵II
题目建议: 本题关键还是在转圈的逻辑,在二分搜索中提到的区间定义,在这里又用上了。
题目链接:59. 螺旋矩阵 II - 力扣(LeetCode)
文章讲解:代码随想录
视频讲解:一入循环深似海 | LeetCode:59.螺旋矩阵II_哔哩哔哩_bilibili
题目
给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
示例 1:

输入:n = 3 输出:[[1,2,3],[8,9,4],[7,6,5]]
示例 2:
输入:n = 1 输出:[[1]]
提示:
1 <= n <= 20
思路
键还是在转圈的逻辑模拟画矩阵的过程,遵循循环不变量原则【我用的是四个边界的方法,两个的没太懂】
top,left=0
bottom,right=n-1
- 填充上行从左到右:【left到right+1】,矩阵元素是【top】【num】行不变;top+1上边界下移
- 填充右列从上到下:【top到bottom+1】矩阵元素是【num】【right】列不变;right-1,右边界左移
- 填充下行从右到左:【right到left-1】(反向)矩阵元素是【bottom】【num】行不变;bottom-1下边界上移
- 填充左列从下到上:【bottom到top-1】(反向)矩阵元素是【num】【left】列不变;left+1左边界右移
上面的边界,因为是range是左闭右开,所以又边界正向要+1,反向要-1
循环条件是left<=right&top<=bottom
遍历二维矩阵,时间复杂度为 O(n^2)
这里的图每层都是左闭右开,但我上面的思路是取到最后一个,然后上边界直接下移,代码也是这样,所以是左闭右闭
- 先填充123,上边界下移到第二行,
- 填充45,右边界移动到前一列,
- 填充67,下边界移动到上一行,
- 填充89


from typing import List
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
if n<=0: return []#n小于等于0时返回空列表
matrix=[[0]*n for _ in range(n)]#创建n*n的矩阵,下划线_表示不考虑变量只考虑循环次数
top,bottom=0,n-1#top表示上边界,bottom表示下边界
left,right=0,n-1#left表示左边界,right表示右边界
num=1#当前填充的数字
while top<=bottom and left<=right:
# 从左到右填充上边界
for i in range(left,right+1):
matrix[top][i]=num
num+=1
top+=1#上边界向下移动一行,第一行填充完毕
# 从上到下填充右边界
for i in range(top,bottom+1):
matrix[i][right]=num#填充右边界,下标从0开始所以最右边不能是[right+1]
num+=1
right-=1#右边界向左移动一列,最右边填充完毕
# 从右到左填充下边界
for i in range(right,left-1,-1):
matrix[bottom][i]=num
num+=1
bottom-=1#下边界向上移动一行,最下边填充完毕
# 从下到上填充左边界
for i in range(bottom,top-1,-1):
matrix[i][left]=num
num+=1
left+=1#左边界向右移动一列,最左边填充完毕
return matrix
# 测试代码
if __name__ == "__main__":
solution = Solution()
n = 3
result = solution.generateMatrix(n)
for row in result:
print(row) # 输出: [[1, 2, 3], [8, 9, 4], [7, 6, 5]]
n1 = 4
result1 = solution.generateMatrix(n1)
for row in result1:
print(row) # 输出: [[1, 2, 3, 4], [12, 13, 14, 5], [11, 16, 15, 6], [10, 9, 8, 7]]
58.区间和
前缀和是一种思维巧妙很实用 而且 很有容易理解的一种算法思想,大家可以体会一下
文章讲解:58. 区间和 | 代码随想录
题目链接:58. 区间和(第九期模拟笔试)
题目
58. 区间和(第九期模拟笔试)
题目描述
给定一个整数数组 Array,请计算该数组在每个指定区间内元素的总和。
输入描述
第一行输入为整数数组 Array 的长度 n,接下来 n 行,每行一个整数,表示数组的元素。随后的输入为需要计算总和的区间下标:a,b (b > = a),直至文件结束。
输出描述
输出每个指定区间内元素的总和。
输入示例
5
1
2
3
4
5
0 1
1 3
输出示例
3
9
提示信息
数据范围:
0 < n <= 100000
思路:前缀和

统计数组的区间和,从0到i,因此:
【0,1】p[1] = vec[0] + vec[1];
【0,5】p[5] = vec[0] + vec[1] + vec[2] + vec[3] + vec[4] + vec[5];
【2,5】p[5] - p[1] = vec[2] + vec[3] + vec[4] + vec[5];注意:如果要求 区间下标 [2, 5] 的区间和,那么应该是 p[5] - p[1],而不是 p[5] - p[2]

步骤:
1.输入:读取键盘上输入的数组长度n和数组元素data[index]
2.计算前缀和:
前缀和数组p中,p[i]表示原数组前i+1个元素的和
一次遍历,时间复杂度为 O (n)
3.区间和查询:
对于查询
[a, b](索引从 0 开始),区间和为p[b] - p[a-1]。若
a=0,则直接返回p[b]。每个查询的时间复杂度为 O (1)
4.输出每个查询的结果
import sys
input=sys.stdin.read#读取键盘上输入的内容
def main():
data=input().split()#将输入的内容按空格分割成列表
index=0#索引
n=int(data[index])#读取数组长度
index+=1
#读取数组元素
vec=[]
for i in range(n):
vec.append(int(data[index+i]))#将输入的内容转换为整数并添加到列表中
#这句中index的值不变,比如第一次一直是1,index表示输入的每一行的第一个数
#是data[index+i]而不是index+=i,index本身不变
index+=n#更新索引,跳过数组元素,这句index才变化
#计算前缀和
p=[0]*n
presum=0#前缀和累加器
for i in range(n):
presum+=vec[i]
p[i]=presum
#p[i]表示vec[0]到vec[i]的和
#p[i]的值是vec[0]到vec[i]的和,p[0]=vec[0],p[1]=vec[0]+vec[1],p[2]=vec[0]+vec[1]+vec[2]...
#处理查询
results=[]#存储查询结果
while index < len(data):#还有数据未处理
l=int(data[index])#读取左边界,比如查询边界为【1,3】
r=int(data[index+1])#读取右边界
index+=2#更新索引,跳过左边界和右边界
#计算区间和
if l == 0:
results.append(p[r])#如果左边界是0,直接返回p[r]
else:
results.append(p[r] - p[l-1])#否则返回p[r] - p[l-1]
#输出结果
for result in results:
print(result)
if __name__ == "__main__":
main()#调用主函数
输入后在空行敲ctrl+Z,然后enter

44. 开发商购买土地
题目
题目描述
在一个城市区域内,被划分成了n * m个连续的区块,每个区块都拥有不同的权值,代表着其土地价值。目前,有两家开发公司,A 公司和 B 公司,希望购买这个城市区域的土地。
现在,需要将这个城市区域的所有区块分配给 A 公司和 B 公司。
然而,由于城市规划的限制,只允许将区域按横向或纵向划分成两个子区域,而且每个子区域都必须包含一个或多个区块。 为了确保公平竞争,你需要找到一种分配方式,使得 A 公司和 B 公司各自的子区域内的土地总价值之差最小。
注意:区块不可再分。
输入描述
第一行输入两个正整数,代表 n 和 m。
接下来的 n 行,每行输出 m 个正整数。
输出描述
请输出一个整数,代表两个子区域内土地总价值之间的最小差距。
输入示例
3 3
1 2 3
2 1 3
1 2 3
输出示例
0
提示信息
如果将区域按照如下方式划分:
1 2 | 3
2 1 | 3
1 2 | 3
两个子区域内土地总价值之间的最小差距可以达到 0。
数据范围:
1 <= n, m <= 100;
n 和 m 不同时为 1。
思路
- 读取矩阵的行数
n和列数m。 - 逐行读取矩阵元素,并计算所有元素的总和
sum。 - 横向切割:计算前
i行的元素和horizontalCut,剩余部分的和为sum - horizontalCut,差值为|sum - 2*horizontalCut|。 - 纵向切割:同理,计算前
j列的元素和verticalCut,差值为|sum - 2*verticalCut| 原理:设矩阵总和为S,切割后的一部分和为T,另一部分和为S - T,则差值为|(S - T) - T| = |S - 2T|。通过遍历所有可能的切割位置,计算每个位置对应的|S - 2T|,取最小值即可。
def main():
import sys
input = sys.stdin.read # 读取键盘上输入的内容
data = input().split() # 将输入的内容按空格分割成列表
index = 0 # 索引
n = int(data[index])# 读取行数
index+=1
m=int(data[index])# 读取列数
index+=1
#计算总合
vec=[]
sum=0
for i in range(n):
row=[]
for j in range(m):
num=int(data[index])# 读取每个数
index+=1
row.append(num)# 将每个数添加到当前行
sum+=num # 累加每个数到总和
vec.append(row)#将每行数据添加到vec中
#vec[i]表示第i行的数据,vec[i][j]表示第i行第j列的数据
# 计算每行和和每列和
# h[i]表示第i行的和,v[j]表示第j列的和
h=[0]*n
for i in range(n):
for j in range(m):
h[i]+=vec[i][j]
v=[0]*m
for j in range(m):
for i in range(n):
v[j]+=vec[i][j]
result=float('inf')# 初始化结果为正无穷大
# 计算最小差值
hsum=0
for i in range(n):
hsum+=h[i]# 累加每行的和
# 计算当前行和的差值
result=min(result,abs((sum-hsum)-hsum))#注意绝对值
vsum=0
for j in range(m):
vsum+=v[j]
result=min(result,abs((sum-vsum)-vsum))
print(result)
if __name__ == "__main__":
main() # 调用主函数
|数组part02&spm=1001.2101.3001.5002&articleId=148613050&d=1&t=3&u=cef91ab0f4654e81a6d2d30305190a3e)
1872

被折叠的 条评论
为什么被折叠?



