测开准备-day02数据结构力扣

看了一下,感觉今天学的都很难,滑动窗口,还有螺旋矩阵。都是我之前没怎么学懂的。不知道学第二遍会怎么样。

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. 第 1 个到第 3 个苹果一共有多少个?(答案:1+2+3=6)

  2. 第 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. 第 1 到第 3 个苹果的和 = 累计到第 3 个的数 - 累计到第 0 个的数 → 6 - 0 = 6

  2. 第 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. 开发商购买土地

题目链接44. 开发商购买土地(第五期模拟笔试)

思路

下面是豆包总结的,我刚开始连题也看不懂

一、题目要你干啥

  1. 给你一块「几行几列」的土地,每个小格子有个价值(比如3行3列,格子值1、2、3这些数);

  2. 只能切一刀(要么横着切、要么竖着切),把土地分成两块,让这两块的总价值差**最小**,最后输出这个最小差值。

二、怎么解决

第一步:算总和

先把所有格子的价值加起来,得到整块土地的总价值(比如你示例里总和是18)。

第二步:试所有切法

  • **横着切**:从第一行下面、第二行下面...依次切,算每一刀的「上半块总价值」,差值=|上半块×2 - 总和|(因为下半块=总和-上半块,差值=|上半块 - (总和-上半块)|);

  • **竖着切**:从第一列右边、第二列右边...依次切,算每一刀的「左半块总价值」,差值=|左半块×2 - 总和|;

第三步:找最小差值

把所有切法的差值放一起,挑最小的那个就是答案。

三、用你的例子走一遍

总和=18

  1. 横着切:
  • 切第一行下:上半块=6 → 差值=|6×2-18|=6;

  • 切第二行下:上半块=12 → 差值=|12×2-18|=6;

  1. 竖着切:
  • 切第一列右:左半块=4 → 差值=|4×2-18|=10;

  • 切第二列右:左半块=9 → 差值=|9×2-18|=0;

  1. 最小差值就是0。

总结

  1. 核心目标:切一刀分两块,找价值差最小的;

  2. 解题步骤:算总和 → 试所有横/竖切法算差值 → 取最小;
    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)

没有力气和手段了

相关推荐
tobias.b11 小时前
计算机基础知识-数据结构
java·数据结构·考研
不想看见40414 小时前
Valid Parentheses栈和队列--力扣101算法题解笔记
开发语言·数据结构·c++
计算机安禾14 小时前
【C语言程序设计】第37篇:链表数据结构(一):单向链表的实现
c语言·开发语言·数据结构·c++·算法·链表·蓝桥杯
皮卡狮15 小时前
高阶数据结构:AVL树
数据结构·算法
不要秃头的小孩15 小时前
50. 随机数排序
数据结构·python·算法
故事和你9116 小时前
sdut-python-实验四-python序列结构(21-27)
大数据·开发语言·数据结构·python·算法
丶小鱼丶17 小时前
数据结构和算法之【栈】
java·数据结构
不要秃头的小孩17 小时前
力扣刷题——111.二叉树的最小深度
数据结构·python·算法·leetcode
散峰而望17 小时前
【基础算法】从入门到实战:递归型枚举与回溯剪枝,暴力搜索的初级优化指南
数据结构·c++·后端·算法·机器学习·github·剪枝