【动态规划】子序列问题二(数组中不连续的一段)

子序列问题二

  • 1.最长定差子序列
  • 2.最长的斐波那契子序列的长度
  • 3.最长等差数列
  • 4.等差数列划分 II - 子序列

在这里插入图片描述

点赞👍👍收藏🌟🌟关注💖💖
你的支持是对我最大的鼓励,我们一起努力吧!😃😃

1.最长定差子序列

题目链接: 1218. 最长定差子序列

题目分析:

在这里插入图片描述
给你一个整数数组 arr 和一个整数 difference,请你找出并返回 arr 中最长等差子序列的长度,该子序列中相邻元素之间的差等于 difference 。

算法原理:

1.状态表示

经验 + 题目要求

dp[i] 表示:以 i 位置的元素为结尾的所有子序列中,最长的等差子序列的长度

2.状态转移方程

设 i 位置里面元素为a,如果以 i 位置元素为结尾研究最长等差子序列的长度,其实 i 位置前面那个元素已经确定了,这道题和最长递增子序列是有区别的,那道题 i 位置前面的元素是要从前往后遍历一遍的来找倒数第二个元素在哪里。这道题已经告诉我们相邻两个元素的差是diff,我只要知道最后一个元素就能推出倒数第二个元素。设倒数第二个元素为b。 a - b = diff —> b = diff - a。

根据 b 存不存在可以分两个情况:

b不存在,a本身就是

b存在,因为是乱序的,前面可能有很多元素等于b,其实我们只需要考虑最后一个b元素的位置就可以了。因为我们想要的是以b元素为结尾的最长等差子序列的长度,最后一个b元素所在位置dp[j1]里面的值至少大于等于前面以b元素为结尾最长等差子序列的长度。然后加上 i 位置的元素。

在这里插入图片描述

这里有个优化:

虽然我们是可以从后往前遍历找到最后一个b元素所在的位置的,但是我们可以这也做,可以之间把 b 元素 和它对应的 dp[i] 放在hash表。就不用去遍历了,可以O(1)的时间复杂度就找到。

  1. 将 元素 + dp[j] 的值,绑定放进哈希表中

甚至我们还可以将 a 元素 + dp[i] 绑定放进哈希表。这样的话就不用要哈希表了。

  1. 直接在哈希表中,做动态规划

3.初始化

我们只需要将以第0个位置元素为结尾子序列,最长的等差子序列的长度初始化一下就行了,反正没得选,就是自己本身。

dp[arr[0]] = 1

4.填表顺序

从左往右

5.返回值

我们要返回的是最长的等差子序列长度,但是这个长度可能在dp表里任意一个位置,因此返回 dp 表里面的最大值

class Solution {
public:
    int longestSubsequence(vector<int>& arr, int difference) {

        // 创建 dp 表
        unordered_map<int,int> hash; //arr[i] - dp[i]
        // 初始化
        hash[arr[0]] = 1;
        //填表
        int ret = 1;
        for(int i = 1; i < arr.size(); ++i)
        {
            //hash[arr[i]]保证b是最新的值
            //hash[arr[i] - difference]保证如果不存在value是0
            hash[arr[i]] = hash[arr[i] - difference] + 1;
            ret = max(ret,hash[arr[i]]);
        }
        return ret;

    }
};

2.最长的斐波那契子序列的长度

题目链接: 873. 最长的斐波那契子序列的长度

题目分析:

在这里插入图片描述

满足斐波那契数列条件,元素长度大于等于3,还有从第三个元素开始,每个元素都等于前两个元素的和,如果序列满足这两个条件我们就称之为斐波那契数列。

在这里插入图片描述
注意这道题给的是严格递增,不仅是递增的而且元素还是不重复的。填表的时候有优化的作用。

算法原理:

1.状态表示

经验 + 题目要求

dp[i] 表示:以 i 位置元素为结尾所有子序列中,最长斐波那契数列子序列的长度

我们尝试用这个状态表示来看看能不能推导出来状态转移方程。

我们是 i 位置来划分问题的,在 0 ~ i -1 任选一个位置 j ,通过 j 位置的 dp[j] ,来更新出 i 位置的dp[i],这是之前做子序列的方法。但是这道题就不行了。我们的状态表示只是表示出来最长斐波那契数列子序列的长度,但是并不知道具体的斐波那契序列。其实如果我们知道最后两个位置的值nums[j],nums[i],我们是能推导出来在前面一个位置的。但是dp[j]根本不知道这个斐波那契数列是什么样。所有我们不能直接用dp[j]的值去更新dp[i]的值。所以上面的状态表示不对!

在这里插入图片描述

通过刚才的分析我们发现,如果在一个斐波那契数列知道最后两个元素,其实是可以把前面所有的元素都推出来的。 … a-(b-a),b-a,b,a。既然单独一个位置为结尾推不出来斐波那契子序列长什么样子,但是如果能用两个元素为结尾就能推出斐波那契子序列长什么样子。一维解决不了问题,在扩一维。

dp[i][j] 表示: 以 i 位置以及 j 位置的元素为结尾的所有子序列中,最长斐波那契子序列长度。 (i 位置 < j 位置)

在这里插入图片描述

2.状态转移方程

如果我们以最后两个位置为结尾,其实我们是可以直接知道倒数第三个数,设倒数第三个数为 a, a = c - b,设 a 的下标为 k

在这里插入图片描述

根据a可以分下面三种情况:

  1. a不存在
  2. a存在且b<a<c
  3. a存在且a<b

a不存在,根本构不成斐波那契子序列,dp[i][j]本应该是0的,但是dp[i][j] 表示以 i,j位置为结尾,至少有两个元素。所以给2。如果dp里面都是2说明,没有都没有构成斐波那契子序列,最后直接返回0就可以了。

a存在且b<a<c,a虽然存在,但是在bc中间,不符合斐波那契数列,所以也是给2。

a存在且a<b,我们要的是最长斐波那契子序列长度,先把 k 位置元素拿出来,,在把 i 位置元素拿出来,先找到以着两个位置元素为结尾的最长斐波那契子序列,后面在加上一个j位置元素就可以了。 而以ki位置元素为结尾最长斐波那契子序列正好在dp[k][j]中,然后再加上1

在这里插入图片描述

优化:找a元素所在位置比较花时间,因此我们将数组中所有元素与它们的下标绑定,存在哈希表中。(数组里面的元素是严格递增,不会存在重复元素)

3.初始化

表里面所有的值都初始化为2,就不用考虑前面两种情况了。
但是细心的会发现不能把表里面的值都初始化为2,dp[0][0] 相当于里面就一个元素,里面的值就是1。其实我们在状态表示就已经规定好了 i < j。对于这个二维dp表,我们只会用到上半部分,

在这里插入图片描述

4.填表顺序

从上到下,从左到右

5.返回值

dp表里面的最大值 ret , ret < 3 ? 0 : ret

class Solution {
public:
    int lenLongestFibSubseq(vector<int>& arr) {

       int n = arr.size();
       //优化
       unordered_map<int,int> hash;
       for(int i = 0; i < n; ++i)
            hash[arr[i]] = i;
        
        int ret = 2;
        vector<vector<int>> dp(n,vector<int>(n,2));
        for(int j = 2; j < n; ++j)// 固定最后⼀个位置
        {
            for(int i = 1; i < j; ++i) // 固定倒数第⼆个位置
            {
                int a = arr[j] - arr[i];
                // 条件成⽴的情况下更新 
                if(a < arr[i] && hash.count(a))
                    dp[i][j] = dp[hash[a]][i] + 1;
                ret = max(ret,dp[i][j]);// 统计表中的最⼤值
            }
        }

        return ret < 3 ? 0 : ret;
    }
};

3.最长等差数列

题目链接: 1027. 最长等差数列

题目分析:

在这里插入图片描述

在数组中找一个子序列,这个子序列要是最长的等差子序列,返回长度。

算法原理:

1.状态表示

经验 + 题目要求

dp[i] 表示:以 i 位置元素为结尾的所有子序列中,最长的等差序列的长度。

接下来以这个状态表示分析一下:能推导出来状态转移方程说明这个状态表示是对的,推导不出来说明这个状态表示是错的。

我想求 以 i 位置元素为结尾的 dp[i] 的值,根据以往的经验 要去 0 ~ i - 1 位置找dp[j]去更新dp[i],但是这道题不行,这道题要找的是 最长的等差序列的长度。而dp[i-1]表示以 i -1 位置元素为结尾的所有子序列中,最长的等差序列的长度。我只知道长度,并不知道等差子序列是什么,这个 i 到底能不能跟在 j 后面是不知道的!因此上面状态表示不对。

如果我们知道等差序列最后两个元素,我们就知道把这个等差序列前面所有元素都推出来,设倒数第一个位置是 a ,倒数第二个位置是 b, 倒数第三个位置为 x,x = 2*a-b。

因此我们的状态表示:

dp[i][j] 表示:以 i 位置以及 j 位置的元素为结尾的所有子序列中,最长的等差序列的长度(i < j)。

2.状态转移方程

设倒数第二个位置 i 位置元素为 b,倒数第一个位置 j 位置元素为 a,我们可以推出来倒数第三个位置 k 位置元素为 a = 2b -c

根据倒数第三个 k 位置可以分为三种情况:

  1. a不存在
  2. a存在,i < k < j
  3. a存在,k < i

a不存在以及a存在,i < k < j(a在bc中间),单独bc就能构成等差子序列,因此长度为2

在这里插入图片描述

a存在,k < i(a < b,在i 位置左边),但是这里又有很多种情况这个a可能有很多个。那这个时候我们需要把所有情况都考虑吗。其实不需要,假设前面最长子序列是以a元素为结尾,那最后一个a所在位置的长度至少大于等于前面的a的长度。所有我们只考虑离 i 位置最近的a就可以了。我们的 k 也表示的是左边离 i 位置最近的那个下标。

在这里插入图片描述

dp[i][j] 表示以 ij 为结尾的最长子序列的长度,这个时候如果发现倒数第三个元素存在并且i左边,是不是可以先找到以 ki 为结尾的最长的长度,然后加一个 j 位置元素就行了,而以 ki 为结尾的最长的长度正好就是 dp[k][i]

在这里插入图片描述

还没完,有没有发现我们找下标k并不是O(1)的时间复杂度。本来dp[i][j] 时间复杂度就已经是O(N ^ 2),又来了一层循环,时间复杂度就变成 O(N ^ 3)。

优化一下:我们要找到的是离 i 位置最近a元素的下标

  1. 在 dp 之前将所有元素 + 下标绑定,放在hash表中,<元素,下标数组>(适合数组中无重复元素)。但是如果这个数据非常恶心,它会把下标数组搞得非常大,时间复杂度依旧是O(N ^ 3)。
    2.一边 dp,一边保存离它最近的元素的下标,<元素,下标>(适合数组中有重复元素)。 这样就是O(1)时间复杂度。

选第二种方式写代码有技巧和填表顺序有关,我们先分析下面的。

3.初始化

表里面所有的值都初始化为2,就不用考虑前面两种情况了。
但是细心的会发现不能把表里面的值都初始化为2,dp[0][0] 相当于里面就一个元素,里面的值就是1。其实我们在状态表示就已经规定好了 i < j。对于这个二维dp表,我们只会用到上半部分,

在这里插入图片描述

4.填表顺序

我们是以i j 位置为结尾,填表也有两种方法:

第一种:

  1. 先固定倒数第一个数
  2. 枚举倒数第二个数

先固定最后一个数 j,枚举倒数第二个数也就是说 i 位置是从0 开始到 j - 1 。当 i = 0 算一下 dp[i][j],当 i = 1 算一下 dp[i][j] 。。。

在这里插入图片描述

第二种:

  1. 先固定倒数第二个数
  2. 枚举倒数第一个数

先固定 i,让 j 从 i + 1 位置开始往后枚举。

在这里插入图片描述

那我们选哪种策略呢?回到优化,一边 dp,一边保存离它最近的元素的下标,<元素,下标>(适合数组中有重复元素)。 如果选择第一种策略会有一种问题,i 位置是一直移动的,那最近的元素也是在一直改变。很难保证是最近的。 所以我们选择第二种初始化方式。当我们固定 i 位置之后,j是往后移动的。当把 i 位置填完之后,ij都会往后移动,我们就可以把i位置的元素存到hash表里。

所以我们选择第二种填表顺序,当 i 位置填完之后,将 i 位置的值放入到hash表中即可。

5.返回值

dp[i][j] 表示以 ij 为结尾的最长子序列的长度,题目要求的是整个子序列中最长的那个。所以返回 dp 表中的最大值。

class Solution {
public:
    int longestArithSeqLength(vector<int>& nums) {
        
        //优化
        unordered_map<int,int> hash;
        hash[nums[0]] = 0;

        int n = nums.size();
        vector<vector<int>> dp(n,vector<int>(n,2));//创建 dp 表 + 初始化
        int ret = 2;
        for(int i = 1; i < n - 1; ++i)//固定倒数第二个数
        {
            for(int j = i + 1; j < n; ++j)//枚举倒数第一个数
            {
                int a = 2 * nums[i] - nums[j];
                if(hash.count(a))
                {
                    dp[i][j] = dp[hash[a]][i] + 1;
                    ret = max(ret,dp[i][j]);
                }
            }
            hash[nums[i]] = i;
        }
        return ret;

    }
};

4.等差数列划分 II - 子序列

题目链接: 446. 等差数列划分 II - 子序列

题目分析:

在这里插入图片描述

给你一个整数数组 nums ,返回 nums 中所有 等差子序列 的数目。

如果一个序列中 至少有三个元素 ,并且任意两个相邻元素之差相同,则称该序列为等差序列。

算法原理:

1.状态表示

经验 + 题目要求

dp[i] 表示 :以 i 位置元素为结尾的所有子序列中,等差子序列的个数

接下来就以这个状态表示看看能不能分析出状态转移方程

以 i 位置元素为结尾的子序列,根据前面的经验 ,有可能是自己本身,有可能是前面 0 ~ i - 1 区间 dp[i - 1],dp[i - 2] … dp[0] 去更新dp[i]进而得到状态转移方程。dp[i - 1] 对应 i - 1 位置元素,dp[i - 2] 对应 i - 2 位置元素… 。,这道题我们要的是等差子序列,要的是 i 位置跟在这些元素的后面,我们的状态表示只是等差子序列的个数,i 位置跟在前面元素后面形成等差子序列,必须要是能跟才行。这个状态表示,我们只知道子序列的个数,但是不能确定一个具体的子序列。 因此这个状态表示不对。重新定义一个状态表示。我们如果等差子序列最后两个位置元素就可以把整个等差子序列推出来了。因此状态表示可以这样定义

dp[i][j] 表示:以 i 位置的元素以及 j 位置的元素为结尾的所有子序列中,等差子序列的个数(i < j)。

2.状态转移方程

设倒数第二个位置 i 位置元素为b,倒数第一个位置 j 位置元素为 c,倒数第三个位置 k位置 元素为a , a = 2b - c

根据 a 可以分三种情况:

  1. a不存在
  2. a存在,i < k < j
  3. a存在,k < i

a不存在,a存在,i < k < j 构不成等差子序列,给0就行了

a存在,k < i,但是这里又有很多种情况这个a可能有很多个。是全都都考虑还是只考虑最后一个位置的a呢?注意我们这里要的是等差子序列的个数,并不是最长等差子序列长度等等。bc可以和前面任意一个a构成等差子序列,因此我们都要考虑。

dp[i][j] 表示以 ij 为结尾的等差子序列的个数,这个时候如果发现倒数第三个元素存在并且i左边,是不是可以先找到以 ki 为结尾的等差子序列个数,然后加一个 j 位置元素就行了,而以 kx i 为结尾的等差子序列个数正好就是 dp[kx][i]然后在加上 j 位置,注意这里求的是个数,因此 dp[i][j] += dp[ki][i] + 1

在这里插入图片描述

这里有个优化:a可能是由重复的,dp[i][j]时间复杂度是O(N ^ 2),如果在遍历去找a时间复杂度就是O(N ^ 3)了,因此

在dp之前,将<元素,下标数组>绑定在一起,放在哈希表中。

3.初始化

最差情况下就是 i j 位置元素为结尾不构成等差子序列,所以可以把dp表里面所有的值都初始化为0

4.填表顺序

  1. 固定倒数第一个数
  2. 枚举倒数第二个数

5.返回值

要的是等差子序列的个数,因此返回 dp 表里面所有元素的和。

class Solution {
public:
    int numberOfArithmeticSlices(vector<int>& nums) {
        int n = nums.size();
        //优化
        unordered_map<long long,vector<int>> hash;
        for(int i = 0; i < n; ++i)
            hash[nums[i]].push_back(i);

        vector<vector<int>> dp(n,vector<int>(n));//创建 dp 表 + 初始化
        int ret = 0;
        for(int j = 2; j < n; ++j)// 固定倒数第⼀个数
        {
            for(int i = 1; i < j; ++i)// 枚举倒数第⼆个数
            {
                long long a = (long long)2 * nums[i] - nums[j];//处理数据溢出
                if(hash.count(a))
                {
                    for(auto k : hash[a])
                    {
                        if(k < i)
                            dp[i][j] += dp[k][i] + 1;
                        else
                            break;

                    }
                    ret += dp[i][j];
                }
            }
        }
        return ret;
        

    }
};

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

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

相关文章

如何提取 R 语言内置数据集和著名 R 包的数据集

大家好&#xff0c;今天我们来聊一聊在 R 语言中如何提取内置数据集&#xff0c;以及如何使用著名 R 包中的数据集。相信很多同学在学习 R 语言时&#xff0c;都会遇到需要用数据集来做练习或者分析的情况。在 R 里&#xff0c;数据集资源非常丰富&#xff0c;R 本身自带了许多…

跨部门SOP与统一知识库:打破信息孤岛,促进团队协作

引言&#xff1a; 在当今这个快速变化且高度竞争的商业环境中&#xff0c;企业面临着前所未有的挑战&#xff0c;其中之一便是如何高效地跨越部门界限&#xff0c;实现无缝协作。传统的组织结构往往导致信息孤岛的出现&#xff0c;不同部门间流程不一致、信息不共享&#xff0…

shader 案例学习笔记之step函数

step函数 step(edge,x)&#xff1a;当x>edge时返回1&#xff0c;否则返回0 #ifdef GL_ES precision mediump float; #endifuniform vec2 u_resolution;void main(){vec2 st gl_FragCoord.xy/u_resolution.xy;float f step(0.5, st.x);gl_FragColor vec4(f, 0, 0, 1.0); …

yolo训练出现Could not load library libcudnn_cnn_train.so.8问题及解决方法

问题场景&#xff1a; 训练yolov5或者yolov8时候会报错&#xff1a; Could not load library libcudnn_cnn_train.so.8. Error: /usr/local/cuda-12.1/lib64/libcudnn_cnn_train.so.8: uined symbol: _ZN5cudnn3cnn34layerNormFwd_execute_internal_implERKNS_7backend11Vari…

web前端-HTML常用标签(三)

一、表格标签 表格是实际开发中非常常用的标签: 1.表格的主要作用&#xff1a; 表格主要用于显示、展示数据&#xff0c;因为它可以让数据显示的非常的规整&#xff0c;可读性非常好。特别是后台展示数据的时候&#xff0c;能够熟练运用表格就显得很重要。一个清爽简约的表格…

火柴人跑酷

运行图片&#xff1a; 这里面有三个boss&#xff0c;和各种元素属性列举一下&#xff1a; 元素作用 火 运用火元素将攻击抵消 水 和火元素一致 磁 自动吸取经验…

MySQL数据表操作

目录 常用数据类型 数值类型 整型 浮点型 字符串类型 日期类型 数据表的操作 查看表结构 创建表 约束 删除表 修改表 添加列 删除列 修改列的定义 重命名列 重命名表 总结 在学习了数据库操作之后&#xff0c;我们接着来看数据表的相关操作 我们首先来学习 …

农产品管理与推荐系统Python+Django网页界面+计算机毕设项目+推荐算法

一、介绍 农产品管理与推荐系统。本系统使用Python作为主要开发语言&#xff0c;前端使用HTML&#xff0c;CSS&#xff0c;BootStrap等技术和框架搭建前端界面&#xff0c;后端使用Django框架处理应用请求&#xff0c;使用Ajax等技术实现前后端的数据通信。实现了一个综合性的…

乡村旅游指标-最美乡村数、旅游示范县数、旅行社数、景区数、农家乐数2007-2021年

2007-2021年乡村旅游指标-最美乡村数、旅游示范县数、旅行社数、景区数、农家乐数.zip资源-CSDN文库https://download.csdn.net/download/2401_84585615/89504677 本文分析的数据集涵盖了中国31个省区市的乡村旅游相关指标&#xff0c;包括从业人数、美丽乡村数量、乡村旅游示…

MPLAB V8.92烧写hex

打开hex文件 File\Import … *.hex文件2. 选择烧录器 Programmer\Select programmer -PICKit3/MPLAB ICD2 3.烧录程序 Programmer\program

ES6标准---【三】【学习ES6看这一篇就够了!!!】

目录 ES6以往文章 ES6之前函数默认值参数的处理方法 ES6函数参数的默认值 与结构赋值默认值结合使用 参数默认值的位置&#xff1a; 函数的length属性 作用域 参数的默认值是一个函数 正确理解函数默认值的例子 应用 指定某一个函数参数不得省略&#xff0c;如果省略…

大模型LLM:合成训练样本的数据分布问题

近几天在研究大模型LLM数数问题时&#xff0c;使用合成数据集来训练LLM“统计字符串&#xff08;100个单词以内&#xff09;中字母的个数”的能力&#xff0c;基于Word进行分词。原始的合成代码在生成随机字符串时&#xff0c;采用如下代码&#xff1a; # self.words为常见英文…

Python安装llama库出错“metadata-generation-failed”

Python安装llama库出错“metadata-generation-failed” 1. 安装llama库时出错2. 定位问题1. 去官网下载llama包 2.修改配置文件2.1 解压文件2.2 修改配置文件 3. 本地安装文件 1. 安装llama库时出错 2. 定位问题 根据查到的资料&#xff0c;发现时llama包中的execfile函数已经…

在职研生活学习--20240907

开学第一天 9月7日&#xff0c;中南大学商学院迎来了一支充满活力的队伍——2024级MBA新生集体整装待发&#xff0c;我们满怀期待地登上了前往长沙望城柏乐园的大巴&#xff0c;准备开启一场为期两天一夜的素质拓展与团队建设之旅。 迎新幼儿园PPT 出发 抵达柏乐园&#xff0c;…

Kubernetes------Service

目录 一、属性说明 二、定义和基本配置 1、定义 2、创建Service 2.1、typeClusterIP 2.2、typeNodePort 2.3、固定IP访问 三、Service、EndPoint、Pod之间的关系 四、服务发现 1、基于Service中IP访问外部服务 2、基于Service中域名访问外部服务 五、Ingress的安装和使…

Caffenie配合Redis做两级缓存

一、什么是两级缓存 在项目中。一级缓存用Caffeine&#xff0c;二级缓存用Redis&#xff0c;查询数据时首先查本地的Caffeine缓存&#xff0c;没有命中再通过网络去访问Redis缓存&#xff0c;还是没有命中再查数据库。具体流程如下 二、简单的二级缓存实现-v1 目录结构 2…

合宙低功耗4G模组AIR780EX ——开发板使用说明

EVB-AIR780EX 开发板是合宙通信推出的基于 Air780EX 模组所开发的&#xff0c;包含电源&#xff0c;SIM 卡&#xff0c;USB&#xff0c;天线&#xff0c;等必要功能的最小硬件系统。 以方便用户在设计前期对Air780E模块进行 性能评估&#xff0c;功能调试&#xff0c;软件开发…

请教一下,安恒信息为什么2024年上半年巨亏2.76亿元?

【科技明说 &#xff5c; 科技热点关注】 根据公开的财务报告来看&#xff0c;安恒信息2024年上半年实现营业总收入6.98亿元&#xff0c;同比增长0.29%。尽管公司在数据安全、商用密码和信创安全等核心业务领域实现了较快增长&#xff0c;但整体上仍然面临亏损。 目前来看&…

blender云渲染来了,blender云渲染教程!

朋友们&#xff0c;成都渲染101农场blender云渲染上线了&#xff0c;继3DMAX/C4D/maya/UE5云渲染上线后&#xff0c;又上线了blender云渲染&#xff0c;今天&#xff0c;成都渲染101渲染农场用四步教会您blender云渲染&#xff01; 第一步&#xff0c;云渲码6666注册个渲染101…

【STM32 HAL库】IIC通信与CubeMX配置

【STM32 HAL库】IIC通信与CubeMX配置 前言理论IIC总线时序图IIC写数据IIC读数据 应用CubeMX配置应用示例AHT20初始化初始化函数读取说明读取函数 前言 本文为笔者学习 IIC 通信的总结&#xff0c;基于keysking的视频内容&#xff0c;如有错误&#xff0c;欢迎指正 理论 IIC总…