【优先算法】专题——前缀和

目录

一、【模版】前缀和

参考代码:

二、【模版】 二维前缀和

参考代码:

三、寻找数组的中心下标

参考代码:

四、除自身以外数组的乘积

参考代码:

五、和为K的子数组

参考代码:

六、和可被K整除的子数组

参考代码:

七、连续数组

参考代码:

八、矩阵区域和

参考代码:

总结


一、【模版】前缀和

【模版】前缀和

题目描述:

数组的元素是从标为1开始的,n是数组的个数,q是查询的次数,查询lr这段区间的和。

解法一:暴力解法,直接查找l到r这段区间之和,但是效率太低,查询q次每次遍历一遍数组时间复杂度O(q*N)n和q的数据范围是1到10^5,暴力解法过不了。

解法二:前缀和,快速求出数组中某一个连续区间的和,时间复杂度O(q)+O(N)

第一步:预处理出来一个前缀和数组,我们要要求1到3的和我们用dp[i-1]+arr[i]就是1到3的和了。

dp[i]表示:表示[1,i]区间内所有元素的和。

dp[i] = dp[i-1] + arr[i]

第二步:使用前缀和数组

如下比如我们要查找l~r这段区间的和那么我们直接去dp数组取出下标为r的这个元素,此元素就是1~r的之和我们减去l-1得到的就是l~r这段区间之和。

这里还有一个问题就是为什么下标要从1开始计数:为了处理边界情况

初始化:添加虚拟结点(辅助结点)

参考代码:

#include <iostream>
#include <vector>
using namespace std;

int main() 
{
    //1.读入数据
    int n,q;
    cin>>n>>q;
    vector<int>arr(n+1);
    for(int i = 1;i<= n;i++) cin>>arr[i];

    //2.预处理出来一个前缀和数组
    vector<long long>dp(n+1); //防止溢出
    for(int i = 0;i<=n;i++) dp[i] = dp[i-1] + arr[i];

    //3.使用前缀和数组
    int l,r;
    while(q--)
    {
        cin>>l>>r;
        cout<<dp[r] -dp[l-1]<<endl;
    }

}

时间复杂度:O(q)+O(n) 


二、【模版】 二维前缀和

题目链接:二维前缀和

题目描述:

题目解析: 

1.从第一行第一列开始到第二列,到二行二列。(如下)

2.从第一行第一列开始到第三列,到三行三列。

3.从第一行第二列开始到4列,到三行四列。

算法原理:

解法一:暴力解法,模拟,让我求哪段区间我就加到哪段区间,如下比如让我们全部求出来那就从头加到尾,时间复杂度高,这道题过不了因为时间复杂度为O(n*m*q)

解法二:前缀和

1.预处理出来一个前缀和矩阵

dp[i][j]表示:从[1,1]位置到[i,j]位置,这段区间里面所有元素和。

如下图我们把它抽象出来,这里我们分为四块面积分别为A、B、C、D,我们要求得dp[i][j]这段区间的和,我们A+B+C+D就等于dp[i][j],我们求B和C这段区间的和是不太好求的,所以我们这样求(A+B) + (A + C) + D - A这里减A是因为多算了一个A所以要减掉,A+B这段区间的值非常好求就是dp[i-1][j]这个位置,A+C就是dp[i][j-1]再加上D这个位置的值就是数组里面的arr[i][j]减去A也就是dp[i-1][j-1],这样就推出了我们预处理的公式。如下图:

2.使用前缀和矩阵

如下假如我们要求D这段区间的和那么我们又被分成了四个部分,竟然要求D这段区间的和我们就A+B+C+D求得结果之后我们先减去上面这部分就是A+B这部分因为A+B这部分可以直接算出了,也就是下图绿色小方块那个位置,在减去A+C这部分但是这样我们发现多减了一个A所以我们要加上一个A,D = A+B+C+D - (A+B)-(A+C)+A(通分之后就等于D),A+B+C+D其实就等于dp[x2][y2]然后减去A+B也就是dp[x1 - 1][y2]再减去A+C也就是dp[x2][y1-1]在加上A也就是dp[x1-1][y1-1],我们直接套用公式就能用O(1)的时间复杂度得出结果。

参考代码:

#include <iostream>
#include <vector>
using namespace std;

int main() 
{
    //1.读入数据
    int n = 0,m = 0,q = 0;
    cin>>n>>m>>q;
    vector<vector<long long>>arr(n+1,vector<long long>(m+1));
    for(int i = 1;i <=n;i++)
        for(int j = 1;j <=m ;j++)
            cin>>arr[i][j];

    //2.预处理前缀和矩阵
    vector<vector<long long>>dp(n+1,vector<long long>(m+1));//防止溢出
    for(int i = 1; i<=n; i++)
        for(int j = 1; j<=m ;j++)
            dp[i][j] = dp[i-1][j] + dp[i][j-1] + arr[i][j] - dp[i-1][j-1];
    

    //3.使用前缀和矩阵
    int x1=0,y1=0,x2=0,y2=0;
    while(q--)
    {
        cin>> x1 >> y1 >> x2 >>y2;
        cout<<dp[x2][y2] - dp[x1-1][y2] - dp[x2][y1-1] + dp[x1-1][y1-1]<<endl;
    }
    return 0;

}

时间复杂为:O(n*m) + O(q)


三、寻找数组的中心下标

题目链接:寻找数组的中心下标

题目描述:

题目解析: 

如下图两边都等于11那么就返回6的下标,如果全是0那么就返回最左边的下标也就是0因为有多个中心下标,不存在则返回-1

解法一:暴力解法,枚举中心下标左边相加的值是否等于右边相加的值,每次枚举一次中心下标都要左边相加右边相加,枚举下标时间复杂O(N),求和依旧使用O(N)的时间复杂度,最终时间复杂度O(N^2)。

解法二:前缀和

我们利用前缀和的思想来实现,竟然要求某一段区间的和那么前缀和预处理出来的那个数组不就可以,我们还要求后面那一段区间的和我们把前缀和改一下改成后缀和就可以了。

我们用f来表示前缀和数组:f[i]表示:[0,i-1]区间,所有元素的和。

f [i]  = f [i-1] + nums[i-1]

g:后缀和数组:g[i]表示:[i+1,n-1]区间,所有元素的和

g [i] = g [i+1] + nums[i+1]

最后进行判断,枚举所有的中心下标从0~n-1然后判断f[i] == g[i],如果有很多中心下标要返回最左边的,所以我们枚举所有的中心下标i,然后判断f[i] == g[i],因为f[i]表示的就是左边所有元素的和g[i]保存的就是右边所有元素的和,判断是否相等如果相等返回i不相等继续往后面找,找到最后一个位置依旧没找到就返回-1

细节问题:

当我们的f等于0的时候我们代入上面发现会越界访问,0~-1这里没有元素所以f(0)= 0

当g等于n-1的时候我们代入上面也会发生越界访问,n-1的右边是没有任何元素的所以g(0) = 0

填写元素顺序,f表是正着填的从左到右,g表是倒着填的从右到左

参考代码:

class Solution {
public:
    int pivotIndex(vector<int>& nums) {
        int n = nums.size();
        vector<int>f(n),g(n);

        //1.预处理前缀和数组以及后缀和数组
        for(int i = 1;i<n;i++)
            f[i] = f[i-1] + nums[i-1];

        for(int j = n-2;j>= 0;j--)
            g[j] = g[j + 1] + nums[j+1];
        
        //2.使用
        for(int i = 0;i<n;i++)
        {
            if(f[i] == g[i])
                return i;
        }
        return -1;
    }
};

时间复杂度:O(N)


四、除自身以外数组的乘积

题目链接:除自身以外数组的乘积

题目描述:

举个例子: 

除1以为2*3*4等于24,除2以外1*3*4等于12,除3以为1*2*4等于8,除4以为1*2*3等于6,题目已经提示我们了使用前缀和 后缀和。

解法一:暴力解法

暴力解法其实和我们上面举的例子一样,比如我们要求除第一个位置以外的值我们就从头遍历尾,要求第二个位置就从第一个开始遍历跳过我们自己然后依次遍历,以此类推。

但是时间复杂度太高了,O(N^2)

解法二:前缀积

本题的思路和上题的思路一样,但是有些细节有变化。

1.预处理前缀积以及后缀积

我们不需要i位置的元素,只要0~i-1位置的元素即可。表示如下:

f:表示前缀积:f [0,i -1 ] 区间内所有元素的乘积

我们要求i-1位置的乘积的时候我们知道i-2位置的乘积让它乘以i-1位置的值就可以了

f[i] = f [i-1] * nums[i-1]

注意:我们上面的f [i-1 ]位置是上图i-2的位置,因为我们f[i]表示的是i-1位置。

我们知道了i+2位置的乘积之后用它乘以i+1位置的值即可。

g:表示后缀积:g[i]表示:[i+1,n-1]

g[i] = g[i+1] * nums[i+1]

2.使用

我们在i这个位置填写数据的时候我们用f[i] * g[i]因为f[i]表示左边的乘积g表示右边的乘积

3.细节问题

当我们i等于0的时候,其实会越界访问所以我们需要处理,那么我们f(0)给什么值合适上面那道题我们给的是0,这道题我们不能给0因为0*nums[i-1]还是0,那么会影响我们的结果所以我们要给1,f(0) = 1,g(n-1) = 1

参考代码:

class Solution {
public:
    vector<int> productExceptSelf(vector<int>& nums) {
        int n = nums.size();
        vector<int>f(n,1),g(n,1);
        vector<int> answer(n);

        //1.预处理前缀积 后缀积
        for(int i = 1;i<n;i++)
            f[i] = f[i-1] * nums[i-1];

        for(int i = n-2;i>=0;i--)
            g[i] = g[i+1] * nums[i+1];
        
        //2.使用
        for(int i = 0;i<n;i++)
        {
            answer[i] = f[i] * g[i];
        }
        return answer;
    }
};

时间复杂度:O(N)


五、和为K的子数组

题目链接:560. 和为 K 的子数组 - 力扣(LeetCode)

题目描述:

前缀和+哈希表

以i位置为结尾的所有的子数组在[0,i-1]区间内,有多少个前缀和等于sum[i] - k就有多少个和为k的子数组,哈希表中分别存储前缀和、次数。

细节问题:

1.在计算i位置之前,哈希表里面只保存[0,i-1]位置的前缀和

2.不用真的创建一个前缀和数组,用一个变量sum来标记前一个位置的前缀和即可

3.如果整个前缀和等于k那么我们需要提前把hash[0] = 1。<0,1>

注意:不能使用滑动窗口来做优化(双指针)因为有0和负数,如下图这种情况我们left不断向右移动,那么有可能中间还有子数组和为 k

参考代码:

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        unordered_map<int,int>hash;
        int sum = 0,ret = 0;
        hash[0] = 1;
        for(auto x : nums)
        {
            sum += x;
            if(hash.count(sum - k)) ret += hash[sum - k];
            hash[sum]++;
        }
        return ret;
    }
};

时间复杂度为 O(n),空间复杂度也为 O(n) 


六、和可被K整除的子数组

题目链接:和可被K整除的子数组

题目描述:

补充知识:

1.同余定理:

(a - b) / p = k.....0    => a % p = b % p

举个例子:(26-12) / 7   =>   26 % 7 = 12 % 7

7 % 2 = 1   -> 7 - 2 = 5 - 2 =3 -2 = 1

取余数的本质就是你这个数有多少个2的倍数就把2的倍数干掉,减到这个数比2小

(1+2 * 3) % 2 = 1(相当于有3个2的倍数,得出等式:(a + p * k) % p = a % p

证明:

(a- b) / p = k

a - b = p * k

a = b + p * k(左右相等,那么左右%p也相等)

a %p = (b + p * k) % p = b % p(p * k有k个p可以直接干掉)

2.C++,java:[负数 % 正数]的结果以及修正

负 % 正 = 负 修正 a % p + p 正负统一(a %p +p) % p(如果a为正数那么就多加了一个p所以再模一个p结果是不变的,如果是负数加上一个p刚好就是正确答案)

我们使用前缀和 + 哈希表

在[0,i-1]区间内,找到有多少个前缀和的余数等于(sun % k + k) % k,哈希表分别存储前缀和的余数、次数

大部分逻辑和上题差不多 

参考代码:

class Solution {
public:
    int subarraysDivByK(vector<int>& nums, int k) {
        unordered_map<int,int>hash;
        hash[0] = 1;//0这个数的余数
        int sum = 0,ret = 0;
        for(auto x : nums)
        {
            sum += x;//算出当前位置的前缀和
            int r = (sum % k + k) % k;//修正后的余数
            if(hash.count(r)) ret +=hash[r%k];//统计结果
            hash[r]++;
        }
        return ret;
    }
};

时间复杂度为 O(n),空间复杂度也为 O(n) 


七、连续数组

题目链接:连续数组

题目描述:

我们把问题转化一下:

1.将所有的0修改为-1

2.在数组中,找出最长的子数组,使子数组中所有的元素和为0

和为k的子数组 ->和为0的子数组

前缀和 + 哈希表

1.哈希表中分别存储前缀和、下标

2.使用完之后,丢进哈希表

3.如果有重复的<sum,i>只保留前面的那一对<sum,i>

4.默认的前缀和为0的情况hash[0] = -1,当我们的这段区间和为sum的时候我们要去0的前面也就是-1的位置找和为0的子区间(存的下标)

5.长度计算i - j + 1 - 1    =>  i - j

参考代码:

class Solution {
public:
    int findMaxLength(vector<int>& nums) {
        unordered_map<int,int> hash;
        hash[0] = -1; //默认有一个前缀和为0的情况
        int sum = 0,ret = 0;
       for(int i = 0 ; i<nums.size();i++)
       {
            sum += nums[i] == 0 ? -1 : 1;
            if(hash.count(sum))  ret = max(ret,i - hash[sum]);
            else hash[sum] = i;
       }
        return ret;

    }
};

八、矩阵区域和

题目链接:矩阵区域和

题目描述:

题目要求:以5为中心分别像上左下右分别扩展k个单位,围城一个长方形的所有元素的和,这是假设k = 1,那么扩展一个单位。

假设求1这个位置,上左下右分别扩展1个单位,然后围成一个正方形,最后相加即可。1+2+4+5

求2这个位置,上左下右分别扩展1个单位然后围成正方形,相加即可,超出矩阵的范围不需要。1+2+3+4+5+6

求5这个位置,上左下右分别扩展1个单位然后围成正方形,相加即可。1+2+3+4+5+6+7+8+9

解法:使用二维前缀和

dp[i][j] = dp[i-1][j]  + dp[i][j-1] -  dp[i-1][j-1] + mat[i][j]

因为多加了一个dp[i-1][j-1]所以再减去一个dp[i-1][j-1]。

如上就是初始化前缀和矩阵的递推公式,直接代入公式即可。

answer= dp[x2][y2] - dp[x1-1][y2] - dp[x2][y1-1] + dp[x1-1][y1-1]

这里加dp[x1-1][y1-1]是因为多减了一个dp[x1-1][y1-1]所以要加上

1.我们要求ans[i][j]位置

我们(i-k,j-k)用(x1,y2)表示

因为这个区间可能会越界,也就是说是(0,0)这个位置的时候我们不能越过,所以我们求一个最大值,如果小于0那么取最大值还是0如果大于0那么就是一个合法的区间。

x1 = max(0,i-k)

y1 = max(0,j-k)

我们(i+k,j+k)用(x2,y2)表示

我们的i+k,j+k可能会超过我们的(m-1,n-1)所以我们需要让它回到我们的m-1,n-1

x2 = min(m-1,i+k)

y2 = min(n-1,j+k) 

2.映射位置 

当我们dp数组要填1,1这个位置的值我们要去mat数组0,0这个位置找。dp(x,y)  -> mat(x-1,y-1)。

所以我们需要把dp[i][j] = dp[i-1][j]  + dp[i][j-1] -  dp[i-1][j-1] + mat[i][j]改为dp[i][j] = dp[i-1][j]  + dp[i][j-1] -  dp[i-1][j-1] + mat[i-1][j-1]

我们在填ans数据的时候使用dp数组需要+1因为ans(0,0)对应dp(1,1)位置。(x,y)  -> (x+1,y+1)。

这里有两种方式:

方法一:

answer[i][j] = dp[x2+1][y2+1] - dp[x1-1+1][y2+1]-dp[x2+1][y1-1+1] +dp [x1-1+1][y1-1+1];

方法二:我们在求下标那里进行+1即可,然后直接在dp数组拿值即可

x1 = max(0,i-k)+1

y1 = max(0,j-k)+1

x2 = min(m-1,i+k)+1

y2 = min(n-1,j+k) +1

参考代码:

class Solution {
public:
    vector<vector<int>> matrixBlockSum(vector<vector<int>>& mat, int k) {
        int m = mat.size(),n = mat[0].size();
        //1.预处理前缀和矩阵
        vector<vector<int>> dp(m+1,vector<int>(n+1));
        for(int i = 1;i <= m;i++)
            for(int j = 1;j<=n;j++)
                dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-1] + mat[i-1][j-1];

        //2.使用
        vector<vector<int>> answer(m,vector<int>(n));
        for(int i = 0;i < m;i++)
        {
            for(int j = 0;j<n;j++)
            {
                int x1 = max(0,i-k) + 1,y1 = max(0,j-k)+1;
                int x2 = min(m-1,i+k) + 1,y2 = min(n-1,j+k)+1;
                answer[i][j] = dp[x2][y2] - dp[x1-1][y2]-dp[x2][y1-1] +dp [x1-1][y1-1];
            }
        }
        return answer;
    }
};

总结

前缀和这个算法,重要思想就是预处理,当我们在解决一个问题的时候不太好解决的时候我们可以先预处理一下,预处理之后在解决效率是非常高的,直接解决时间复杂度是N^2级别,预处理一下直接变O(N),这种就是典型的用空间换时间,因为我们多创建了一个数组,但是时间复杂度提高了一个级别。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/963951.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

刷题记录 动态规划-6: 62. 不同路径

题目&#xff1a;62. 不同路径 难度&#xff1a;中等 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#x…

梯度、梯度下降、最小二乘法

在求解机器学习算法的模型参数&#xff0c;即无约束优化问题时&#xff0c;梯度下降是最常采用的方法之一&#xff0c;另一种常用的方法是最小二乘法。 1. 梯度和梯度下降 在微积分里面&#xff0c;对多元函数的参数求∂偏导数&#xff0c;把求得的各个参数的偏导数以向量的形式…

基于STM32的智能安防监控系统

1. 引言 随着物联网技术的普及&#xff0c;智能安防系统在家庭与工业场景中的应用日益广泛。本文设计了一款基于STM32的智能安防监控系统&#xff0c;集成人体感应、环境异常检测、图像识别与云端联动功能&#xff0c;支持实时报警、远程监控与数据回溯。该系统采用边缘计算与…

优化代码性能:利用CPU缓存原理

在计算机的世界里&#xff0c;有一场如同龟兔赛跑般的速度较量&#xff0c;主角便是 CPU 和内存 。龟兔赛跑的故事大家都耳熟能详&#xff0c;兔子速度飞快&#xff0c;乌龟则慢吞吞的。在计算机中&#xff0c;CPU 就如同那敏捷的兔子&#xff0c;拥有超高的运算速度&#xff0…

Notepad++消除生成bak文件

设置(T) ⇒ 首选项... ⇒ 备份 ⇒ 勾选 "禁用" 勾选禁用 就不会再生成bak文件了 notepad怎么修改字符集编码格式为gbk 如图所示

如何创建折叠式Title

文章目录 1 概念介绍2 使用方法3 示例代码 我们在上一章回中介绍了SliverGrid组件相关的内容&#xff0c;本章回中将介绍SliverAppBar组件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1 概念介绍 我们在本章回中介绍的SliverAppBar和普通的AppBar类似&#xff0c;它们的…

K个不同子数组的数目--滑动窗口--字节--亚马逊

Stay hungry, stay foolish 题目描述 给定一个正整数数组 nums和一个整数 k&#xff0c;返回 nums 中 「好子数组」 的数目。 如果 nums 的某个子数组中不同整数的个数恰好为 k&#xff0c;则称 nums 的这个连续、不一定不同的子数组为 「好子数组 」。 例如&#xff0c;[1,2,…

Chromium132 编译指南 - Android 篇(一):编译前准备

1. 引言 欢迎来到《Chromium 132 编译指南 - Android 篇》系列的第一部分。本系列指南将引导您逐步完成在 Android 平台上编译 Chromium 132 版本的全过程。Chromium 作为一款由 Google 主导开发的开源浏览器引擎&#xff0c;为众多现代浏览器提供了核心驱动力。而 Android 作…

webpack传输性能优化

手动分包 基本原理 手动分包的总体思路是&#xff1a;先打包公共模块&#xff0c;然后再打包业务代码。 打包公共模块 公共模块会被打包成为动态链接库&#xff08;dll Dynamic Link Library&#xff09;&#xff0c;并生成资源清单。 打包业务代码 打包时&#xff0c;如果…

6 [新一代Github投毒针对网络安全人员钓鱼]

0x01 前言 在Github上APT组织“海莲花”发布存在后门的提权BOF&#xff0c;通过该项目针对网络安全从业人员进行钓鱼。不过其实早在几年前就已经有人对Visual Studio项目恶意利用进行过研究&#xff0c;所以投毒的手法也不算是新的技术。但这次国内有大量的安全从业者转发该钓…

加载数据,并切分

# Step 3 . WebBaseLoader 配置为专门从 Lilian Weng 的博客文章中抓取和加载内容。它仅针对网页的相关部分&#xff08;例如帖子内容、标题和标头&#xff09;进行处理。 加载信息 from langchain_community.document_loaders import WebBaseLoader loader WebBaseLoader(w…

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.5 高级索引应用:图像处理中的区域提取

2.5 高级索引应用&#xff1a;图像处理中的区域提取 目录/提纲 #mermaid-svg-BI09xc20YqcpUam7 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-BI09xc20YqcpUam7 .error-icon{fill:#552222;}#mermaid-svg-BI09xc20…

房屋中介管理系统的设计与实现

房屋中介管理系统的设计与实现 摘要&#xff1a;随着房地产市场的快速发展&#xff0c;房屋中介行业的信息管理需求日益增长。传统的管理方式已无法满足中介公司对房源信息、客户信息以及业务流程的高效管理需求。为此&#xff0c;本文设计并实现了一套房屋中介管理系统&#x…

Vue指令v-on

目录 一、Vue中的v-on指令是什么&#xff1f;二、v-on指令的简写三、v-on指令的使用 一、Vue中的v-on指令是什么&#xff1f; v-on指令的作用是&#xff1a;为元素绑定事件。 二、v-on指令的简写 “v-on&#xff1a;“指令可以简写为”” 三、v-on指令的使用 1、v-on指令绑…

力扣第435场周赛讲解

文章目录 题目总览题目详解3442.奇偶频次间的最大差值I3443.K次修改后的最大曼哈顿距离3444. 使数组包含目标值倍数的最少增量3445.奇偶频次间的最大差值 II 题目总览 奇偶频次间的最大差值I K次修改后的最大曼哈顿距离 使数组包含目标值倍数的最少增量 奇偶频次间的最大差值I…

编程AI深度实战:给vim装上AI

系列文章&#xff1a; 编程AI深度实战&#xff1a;私有模型deep seek r1&#xff0c;必会ollama-CSDN博客 编程AI深度实战&#xff1a;自己的AI&#xff0c;必会LangChain-CSDN博客 编程AI深度实战&#xff1a;给vim装上AI-CSDN博客 编程AI深度实战&#xff1a;火的编程AI&…

嵌入式知识点总结 操作系统 专题提升(四)-上下文

针对于嵌入式软件杂乱的知识点总结起来&#xff0c;提供给读者学习复习对下述内容的强化。 目录 1.上下文有哪些?怎么理解? 2.为什么会有上下文这种概念? 3.什么情况下进行用户态到内核态的切换? 4.中断上下文代码中有哪些注意事项&#xff1f; 5.请问线程需要保存哪些…

python算法和数据结构刷题[6]:二叉树、堆、BFS\DFS

遍历二叉树 前序遍历NLR&#xff1a;先访问根结点&#xff0c;再前序遍历左子树&#xff0c;最后前序遍历右子树。中序遍历LNR&#xff1a;先中序遍历左子树&#xff0c;再访问根结点&#xff0c;最后中序遍历右子树。后序遍历 LRN&#xff1a;先后序遍历左子树&#xff0c;再…

012-51单片机CLD1602显示万年历+闹钟+农历+整点报时

1. 硬件设计 硬件是我自己设计的一个通用的51单片机开发平台&#xff0c;可以根据需要自行焊接模块&#xff0c;这是用立创EDA画的一个双层PCB板&#xff0c;所以模块都是插针式&#xff0c;不是表贴的。电路原理图在文末的链接里&#xff0c;PCB图暂时不选择开源。 B站上传的…

w191教师工作量管理系统的设计与实现

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;原创团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339;赠送计算机毕业设计600个选题excel文…