看了一下,感觉今天学的都很难,滑动窗口,还有螺旋矩阵。都是我之前没怎么学懂的。不知道学第二遍会怎么样。
209.长度最小的子数组
题目链接209. 长度最小的子数组 - 力扣(LeetCode)
思路
暴力解法:两个for循环,一个控制起始位置,一个控制结束位置。然后计算得到所有区间,再比较得到最小的区间
如果用一个循环如何实现?
如果循环里面的一个变量j表示起点,那另一个终点位置是否需要把所有都遍历一遍,那和暴力解法没有区别。
那如果将循环里面的一个变量j作为终点位置,起点位置又该怎么变化。当我们发现区间里面的元素之和大于等于s,收集结果,就可以去改变起始位置
伪代码的方式
python
//j是终止位置,i是起始位置
i=0
result=max//给他初始化一个最大值,他可以在后面的代码里面进行更新
for(j=0;j<=numsize;j++)
sum+=nums[j]//sum是区间里面的元素和
while(sum>=s)
subl=j-i+1//区间长度
result=min(result,subl)//取最小值
sum=sum-nums[i]//移动起始位置,往右边移,移出区间的数值就减去
i++
//while(sum>=s)这里为什么不写if。如果这种情况[1,1,1,1,100]找大于100的最小区间,当终止位置移到100,起始位置只移一位并不能得到最小区间,需要持续去移动
return result
写题

1.我没招了,自己写的时候把i=i+1,写成了i=i-1
2.还有问题是这里把result=len(nums),如果这个数据里面一个符合条件的都没有,返回的结果就有问题
把初始条件改了一下,加上了下面这段
python
if result==len(nums)+1:
return 0

相关题目

59.螺旋矩阵II
题目链接59. 螺旋矩阵 II - 力扣(LeetCode)
思路
重点是正方形4个拐角位置的处理,其实这里需要统一处理规则
就像昨天二分法左闭右闭,或者左闭右开,一开始选择,后面就按这种规则写,不能一会这个一会那个,把自己也给绕晕了。
这里选择先处理每条边的开始和中间,但是不处理这条边最后一个元素
这条边最后一个元素作为下一次处理的开始
可以看一下这个图,一种颜色处理一次

伪代码

补一个数组的索引图,太久没看有点混乱
python
startx=0
starty=0
offset=1
count=1//计数的
while(n/2){
for(j=starty;j<n-offset;j++)//第1条边
nums[startx][j]=count++//这一行startx不变,j变,赋值
for(i=startx;i<n-offset;i++)//第2条边
nums[i][j]=count++
for(;j>starty;j--)//j没有初始化,因为已经走到这个点了
nums[i][j]=count++
for(;i>startx;i--)
nums[i][j]=count++
startx++
starty++
offset++ //每转完一圈更新
}
if n%2==1:
nums[i][j]=count//n是奇数的话,转到最后会剩一个元素,直接填充
写题

python
# 初始化一个 n x n 的列表,初始值设为 0(你可以替换成任意初始值,比如 None、1 等)
matrix = [[0 for _ in range(n)] for _ in range(n)]

这里把for改成了while

python
原代码 while(n/2):比如 n=3 时,n/2=1.0,布尔值为 True,会无限循环;
修复后 for _ in range(n//2):n=3 时循环 1 圈,n=4 时循环 2 圈,刚好覆盖所有非中心的位置。

终于能把代码跑通了,输出有点问题,再检查一下
只有最中间那个9错了

好像循环都没什么问题,只是写的有点冗余,可以看一下,就是我这边和伪代码还有一个不同是,我把开始循环的开始start统一了,边界就是用的n-offset,然后循环变量都是在这个区间(start和n-offset)变化
python
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
startx=0
starty=0
i=j=0
count=1
offset=1
nums = [[0 for _ in range(n)] for _ in range(n)]
for _ in range(n//2):
j=starty
while(j<n-offset):
nums[startx][j]=count
count=count+1
j=j+1
i=startx
while(i<n-offset):
nums[i][n-offset]=count
count=count+1
i=i+1
j=n-offset
while(j>starty):
nums[n-offset][j]=count
count=count+1
j=j-1
i=n-offset
while(i>startx):
nums[i][starty]=count
count=count+1
i=i-1
startx+=1
starty+=1
offset+=1
if n%2==1:
center=n//2
nums[center][center]=count
return nums
58.区间和
题目链接58. 区间和(第九期模拟笔试)
思路

第一步:先搞懂题目到底要做什么(生活化例子)
假设你有 5 个苹果,数量分别是:[1, 2, 3, 4, 5]现在有 2 个问题要问你:
-
第 1 个到第 3 个苹果一共有多少个?(答案:1+2+3=6)
-
第 2 个到第 4 个苹果一共有多少个?(答案:2+3+4=9)
这道题的本质就是:给你一串数字,再问你若干次「某个区间内的数字总和」,你要快速算出答案。
第二步:为什么不用「每次都加一遍」?(引出核心思路)
如果数字少(比如只有 5 个),每次问都手动加一遍没问题,但如果有 10000 个数字、问 10000 次,每次都加一遍会特别慢。
所以我们要学一个「偷懒技巧」------前缀和,就像提前算好「累计数」,后面查的时候直接减一下就行。
前缀和怎么理解?(还是用苹果举例)
我们先做一个「累计苹果数列表」(前缀和数组):
-
第 0 个位置:0(没拿苹果)
-
第 1 个位置:1(只拿第 1 个苹果)
-
第 2 个位置:1+2=3(拿第 1+2 个苹果)
-
第 3 个位置:1+2+3=6(拿第 1+2+3 个苹果)
-
第 4 个位置:1+2+3+4=10(拿第 1-4 个苹果)
-
第 5 个位置:1+2+3+4+5=15(拿全部 5 个苹果)
这个累计列表就是「前缀和数组」:[0, 1, 3, 6, 10, 15]
现在回答问题就快了:
-
第 1 到第 3 个苹果的和 = 累计到第 3 个的数 - 累计到第 0 个的数 → 6 - 0 = 6
-
第 2 到第 4 个苹果的和 = 累计到第 4 个的数 - 累计到第 1 个的数 → 10 - 1 = 9
核心公式 :求「第 l 个到第 r 个」的和 = 前缀和 [r] - 前缀和 [l-1]
写题
python
n=int(input())
nums=[0]*n
for i in range(n):
nums[i]=int(input())
res=[0]*n
for i in range(n):
res[i]=sum(nums[0:i+1])
while(1):
a,b=input().split(' ')
a=int(a)
b=int(b)
if a==0:
print(res[b])
else:
print(res[b]-res[a-1])
我的代码写成这个样子,但是最后退出的时候有问题。另外其实a的取值也是需要判断的,这里我刚开始写错了然后计算的结果不对。

然后让AI给我改了一下
python
while True:
try:
a, b = map(int, input().split())
if a == 0:
print(res[b])
else:
print(res[b] - res[a-1])
except EOFError:
break # 捕获到输入结束,退出循环
好的,时间超过限制

去掉了while(1)的循环,引入了区间查询

python
n = int(input())
nums = [0] * n
for i in range(n):
nums[i] = int(input())
# 构建前缀和数组(和你原来的 res 逻辑一致)
res = [0] * n
res[0] = nums[0]
for i in range(1, n):
res[i] = res[i-1] + nums[i]
# 处理区间查询,直到输入结束
import sys
for line in sys.stdin:
line = line.strip()
if not line: # 跳过空行
continue
a, b = map(int, line.split())
if a == 0:
print(res[b])
else:
print(res[b] - res[a-1])
44. 开发商购买土地
思路

下面是豆包总结的,我刚开始连题也看不懂
一、题目要你干啥
-
给你一块「几行几列」的土地,每个小格子有个价值(比如3行3列,格子值1、2、3这些数);
-
只能切一刀(要么横着切、要么竖着切),把土地分成两块,让这两块的总价值差**最小**,最后输出这个最小差值。
二、怎么解决
第一步:算总和
先把所有格子的价值加起来,得到整块土地的总价值(比如你示例里总和是18)。
第二步:试所有切法
-
**横着切**:从第一行下面、第二行下面...依次切,算每一刀的「上半块总价值」,差值=|上半块×2 - 总和|(因为下半块=总和-上半块,差值=|上半块 - (总和-上半块)|);
-
**竖着切**:从第一列右边、第二列右边...依次切,算每一刀的「左半块总价值」,差值=|左半块×2 - 总和|;
第三步:找最小差值
把所有切法的差值放一起,挑最小的那个就是答案。
三、用你的例子走一遍
总和=18
- 横着切:
-
切第一行下:上半块=6 → 差值=|6×2-18|=6;
-
切第二行下:上半块=12 → 差值=|12×2-18|=6;
- 竖着切:
-
切第一列右:左半块=4 → 差值=|4×2-18|=10;
-
切第二列右:左半块=9 → 差值=|9×2-18|=0;
- 最小差值就是0。
总结
-
核心目标:切一刀分两块,找价值差最小的;
-
解题步骤:算总和 → 试所有横/竖切法算差值 → 取最小;
3. 关键技巧:用「半块×2 - 总和」算差值,不用算两块的差,更省事。
这个第三步我刚刚推了一下,比如一块是6,一块就是总和-6,那他们的差值就是(总和-6)-6的绝对值,就是这个「半块×2 - 总和」算差值
题解
python
# 第一步:读取输入的行数和列数(比如3 3)
n, m = map(int, input().split())
# 第二步:读取土地价值,存成二维列表(网格)
land = []
total = 0 # 记录所有土地的总价值
for _ in range(n):
# 读取一行的数字,转成整数列表
row = list(map(int, input().split()))
land.append(row)
# 累加这一行的价值到总价值里
total += sum(row)
# 第三步:找所有切法的最小差值(初始设为很大的数)
min_diff = float('inf')
# ===== 先试所有横向切法(按行切)=====
row_sum = 0 # 累计上面半块的价值
for i in range(n-1): # 只能切n-1次(比如3行只能切2次)
# 加上第i行的价值(i从0开始,对应第1行)
row_sum += sum(land[i])
# 计算差值:|上半块 - 下半块| = |row_sum - (total - row_sum)| = |2*row_sum - total|
diff = abs(2 * row_sum - total)
# 更新最小差值
if diff < min_diff:
min_diff = diff
# ===== 再试所有纵向切法(按列切)=====
col_sum = 0 # 累计左边半块的价值
for j in range(m-1): # 只能切m-1次(比如3列只能切2次)
# 累加第j列的价值
col_val = 0
for i in range(n):
col_val += land[i][j]
col_sum += col_val
# 计算差值
diff = abs(2 * col_sum - total)
# 更新最小差值
if diff < min_diff:
min_diff = diff
# 第四步:输出最小差值
print(min_diff)
没有力气和手段了