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

news2025/3/14 12:15:17

目录

一、【模版】前缀和

参考代码:

二、【模版】 二维前缀和

参考代码:

三、寻找数组的中心下标

参考代码:

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

参考代码:

五、和为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),这种就是典型的用空间换时间,因为我们多创建了一个数组,但是时间复杂度提高了一个级别。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】使用管道实现一个简易版本的进程池

文章目录 使用管道实现一个简易版本的进程池流程图代码makefileTask.hppProcessPool.cc 程序流程&#xff1a; 使用管道实现一个简易版本的进程池 流程图 代码 makefile ProcessPool:ProcessPool.ccg -o $ $^ -g -stdc11 .PHONY:clean clean:rm -f ProcessPoolTask.hpp #pr…

找不到msvcp140.dll解决方法

您可以尝试以下方案进行修复&#xff0c;看看是否可以解决这个问题&#xff1a; 一、重新注册 msvcp140.dll 运行库文件&#xff1a; “WinR”打开运行&#xff0c;键入&#xff1a;regsvr32 MSVCP140.dll&#xff0c;回车即可&#xff1b; 如果出现找不到该文件的提示&…

【优先算法】专题——位运算

在讲解位运算之前我们来总结一下常见的位运算 一、常见的位运算 1.基础为运算 << &&#xff1a;有0就是0 >> |&#xff1a;有1就是1 ~ ^&#xff1a;相同为0&#xff0c;相异位1 /无进位相加 2.给一个数 n&#xff0c;确定它的二进制表示…

【Cadence仿真技巧学习笔记】求解65nm库晶体管参数un, e0, Cox

在设计放大器的第一步就是确定好晶体管参数和直流工作点的选取。通过阅读文献&#xff0c;我了解到L波段低噪声放大器的mos器件最优宽度计算公式为 W o p t . p 3 2 1 ω L C o x R s Q s p W_{opt.p}\frac{3}{2}\frac{1}{\omega LC_{ox}R_{s}Q_{sp}} Wopt.p​23​ωLCox​Rs…

Docker入门篇(Docker基础概念与Linux安装教程)

目录 一、什么是Docker、有什么作用 二、Docker与虚拟机(对比) 三、Docker基础概念 四、CentOS安装Docker 一、从零认识Docker、有什么作用 1.项目部署可能的问题&#xff1a; 大型项目组件较多&#xff0c;运行环境也较为复杂&#xff0c;部署时会碰到一些问题&#xff1…

开源智慧园区管理系统对比其他十种管理软件的优势与应用前景分析

内容概要 在当今数字化快速发展的时代&#xff0c;园区管理软件的选择显得尤为重要。而开源智慧园区管理系统凭借其独特的优势&#xff0c;逐渐成为用户的新宠。与传统管理软件相比&#xff0c;它不仅灵活性高&#xff0c;而且具有更强的可定制性&#xff0c;让各类园区&#…

【C++】P5734 【深基6.例6】文字处理软件

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目描述&#x1f4af;题目描述输入格式输出格式示例输入与输出输入&#xff1a;输出&#xff1a; &#x1f4af;我的做法操作1&#xff1a;在文档末尾插入字符串操作2&…

CSS核心

CSS的引入方式 内部样式表是在 html 页面内部写一个 style 标签&#xff0c;在标签内部编写 CSS 代码控制整个 HTML 页面的样式。<style> 标签理论上可以放在 HTML 文档的任何地方&#xff0c;但一般会放在文档的 <head> 标签中。 <style> div { color: r…

013-51单片机红外遥控器模拟控制空调,自动制冷制热定时开关

主要功能是通过红外遥控器模拟控制空调&#xff0c;可以实现根据环境温度制冷和制热&#xff0c;能够通过遥控器设定温度&#xff0c;可以定时开关空调。 1.硬件介绍 硬件是我自己设计的一个通用的51单片机开发平台&#xff0c;可以根据需要自行焊接模块&#xff0c;这是用立创…

CMake项目编译与开源项目目录结构

Cmake 使用简单方便&#xff0c;可以跨平台构建项目编译环境&#xff0c;尤其比直接写makefile简单&#xff0c;可以通过简单的Cmake生成负责的Makefile文件。 如果没有使用cmake进行编译&#xff0c;需要如下命令&#xff1a;&#xff08;以muduo库echo服务器为例&#xff09;…

OPENPPP2 —— VMUX_NET 多路复用原理剖析

在阅读本文之前&#xff0c;必先了解以下几个概念&#xff1a; 1、MUX&#xff08;Multiplexer&#xff09;&#xff1a;合并多个信号到单一通道。 2、DEMUX&#xff08;Demultiplexer&#xff09;&#xff1a;从单一通道分离出多个信号。 3、单一通道&#xff0c;可汇聚多个…

语言月赛 202412【正在联系教练退赛】题解(AC)

》》》点我查看「视频」详解》》》 [语言月赛 202412] 正在联系教练退赛 题目背景 在本题中&#xff0c;我们称一个字符串 y y y 是一个字符串 x x x 的子串&#xff0c;当且仅当从 x x x 的开头和结尾删去若干个&#xff08;可以为 0 0 0 个&#xff09;字符后剩余的字…

【数据结构】_链表经典算法OJ:复杂链表的复制

目录 1. 题目链接及描述 2. 解题思路 3. 程序 1. 题目链接及描述 题目链接&#xff1a;138. 随机链表的复制 - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机指针 random &#xff0c;…

python的pre-commit库的使用

在软件开发过程中&#xff0c;保持代码的一致性和高质量是非常重要的。pre-commit 是一个强大的工具&#xff0c;它可以帮助我们在提交代码到版本控制系统&#xff08;如 Git&#xff09;之前自动运行一系列的代码检查和格式化操作。通过这种方式&#xff0c;我们可以确保每次提…

【C语言入门】解锁核心关键字的终极奥秘与实战应用(三)

目录 一、auto 1.1. 作用 1.2. 特性 1.3. 代码示例 二、register 2.1. 作用 2.2. 特性 2.3. 代码示例 三、static 3.1. 修饰局部变量 3.2. 修饰全局变量 3.3. 修饰函数 四、extern 4.1. 作用 4.2. 特性 4.3. 代码示例 五、volatile 5.1. 作用 5.2. 代码示例…

音标-- 02-- 重音 音节 变音

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 国际音标1.重音2.音节3.变音 国际音标 1.重音 2.音节 3.变音

[STM32 标准库]EXTI应用场景 功能框图 寄存器

一、EXTI 外部中断在嵌入式系统中有广泛的应用场景&#xff0c;如按钮开关控制&#xff0c;传感器触发&#xff0c;通信接口中断等。其原理都差不多&#xff0c;STM32会对外部中断引脚的边沿进行检测&#xff0c;若检测到相应的边沿会触发中断&#xff0c;在中断中做出相应的处…

C语言练习【互斥锁、信号量线程同步、条件变量实现生产者消费者模型】

练习1 请使用互斥锁 和 信号量分别实现5个线程之间的同步 互斥锁实现同步 #include <stdio.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>…

w190工作流程管理系统设计与实现

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

linux下ollama更换模型路径

Linux下更换Ollama模型下载路径指南   在使用Ollama进行AI模型管理时&#xff0c;有时需要根据实际需求更改模型文件的存储路径。本文将详细介绍如何在Linux系统中更改Ollama模型的下载路径。 一、关闭Ollama服务   在更改模型路径之前&#xff0c;需要先停止Ollama服务。…