【动态规划】子序列问题二(数组中不连续的一段)
子序列问题二
- 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)的时间复杂度就找到。
- 将 元素 + dp[j] 的值,绑定放进哈希表中
甚至我们还可以将 a 元素 + dp[i] 绑定放进哈希表。这样的话就不用要哈希表了。
- 直接在哈希表中,做动态规划
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是0hash[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可以分下面三种情况:
- a不存在
- a存在且b<a<c
- 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 位置可以分为三种情况:
- a不存在
- a存在,i < k < j
- 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元素的下标
- 在 dp 之前将所有元素 + 下标绑定,放在hash表中,<元素,下标数组>(适合数组中无重复元素)。但是如果这个数据非常恶心,它会把下标数组搞得非常大,时间复杂度依旧是O(N ^ 3)。
2.一边 dp,一边保存离它最近的元素的下标,<元素,下标>(适合数组中有重复元素)。 这样就是O(1)时间复杂度。
选第二种方式写代码有技巧和填表顺序有关,我们先分析下面的。
3.初始化
表里面所有的值都初始化为2,就不用考虑前面两种情况了。
但是细心的会发现不能把表里面的值都初始化为2,dp[0][0] 相当于里面就一个元素,里面的值就是1。其实我们在状态表示就已经规定好了 i < j。对于这个二维dp表,我们只会用到上半部分,

4.填表顺序
我们是以i j 位置为结尾,填表也有两种方法:
第一种:
- 先固定倒数第一个数
- 枚举倒数第二个数
先固定最后一个数 j,枚举倒数第二个数也就是说 i 位置是从0 开始到 j - 1 。当 i = 0 算一下 dp[i][j],当 i = 1 算一下 dp[i][j] 。。。

第二种:
- 先固定倒数第二个数
- 枚举倒数第一个数
先固定 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 可以分三种情况:
- a不存在
- a存在,i < k < j
- 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.填表顺序
- 固定倒数第一个数
- 枚举倒数第二个数
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;elsebreak;}ret += dp[i][j];}}}return ret;}
};
相关文章:
【动态规划】子序列问题二(数组中不连续的一段)
子序列问题二 1.最长定差子序列2.最长的斐波那契子序列的长度3.最长等差数列4.等差数列划分 II - 子序列 点赞👍👍收藏🌟🌟关注💖💖 你的支持是对我最大的鼓励,我们一起努力吧!😃&am…...
可视耳勺方便吗?可视耳勺热销第一名品牌!
在生活中,耳部清洁是我们常常会关注却又容易忽视细节的一项日常护理。传统挖耳勺有着不可视的局限性,只能凭感觉和经验反复刮蹭耳朵,很容易将耳垢越捅越深,而且还会刮伤耳道。因此,可视耳勺应运而生,它通过…...
micropython 3-wire spi 9bit 写入的问题
网上猛找把,没有,找不到,mpy不愧是没朋友的缩写,没有咋办,自己造! 此库特别适用那些rgb屏的初始化,大多用3线spi,好家伙rgb用了十多个引脚现在想起来省引脚了是吧,就差这…...
导致JVM内存泄露的ThreadLocal详解
1. ThreadLocal介绍 1.1 什么是ThreadLocal Java官方文档中的描述:ThreadLocal类用来提供线程内部的局部变量。这种变量在多线程环境下访问(通过get和set方法访问)时能保证各个线程的变量相对独立于其他线程内的变量。ThreadLocal实例通常来…...
windows下关闭解除占用端口的进程
环境:windows 10 场景:启动某一应用程序时,提示其他应用已占用此端口,比如端口2425。 解决步骤: 1/3、打开windows的命令提示符,输入以下命令,查找占用此端口2425的PID号: # win…...
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK获取相机当前数据吞吐量(Python)
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK里函数来获取相机当前数据吞吐量(Python) Baumer工业相机Baumer工业相机的数据吞吐量的技术背景CameraExplorer如何查看相机吞吐量信息在NEOAPI SDK里通过函数获取相机接口吞吐量 Baumer工业相机通过NEOAPI…...
版权与开源协议:一场创新与自由的边界之争
在数字时代的浪潮中,版权与开源协议作为知识产权领域的两大支柱,既相互依存又暗自较劲,共同绘制着科技创新的宏伟蓝图。本文将带您深入这场创新与自由的边界之争,探讨版权与开源协议之间的微妙关系,以及它们如何共同推…...
学生用的蓝牙耳机推荐有哪些?实测四款实力出众机型!
在当今数字化学习环境中,学生对蓝牙耳机的需求日益增长,无论是在线课程的学习、图书馆的集中阅读还是日常通勤中的音频资料复习,一款性能优异、舒适度高且价格合理的蓝牙耳机对学生来说至关重要,面对市场上琳琅满目的产品选择&…...
MIT6.824 课程-GFS
GFS 原文:https://zhuanlan.zhihu.com/p/113161014 搬运用于参考学习 概述 存储(Storage)是一个非常关键的抽象,用途广泛。 GFS 论文还提到了很多关于容错、备份和一致性的问题。 GFS 本身是 Google 内部一个很成功的实用系统&…...
力扣第200题 岛屿数量
前言 记录一下刷题历程 力扣第200题 岛屿数量 岛屿数量 原题目: 给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。 岛屿总是被水包围,并且每座岛屿只能由水平…...
协议头,wireshark,http
目录 协议头 ip头 udp头 mac层 网络工具 telnet wireshark Http 一、HTTP 协议介绍 二、HTTP 协议的工作过程 三、使用抓包工具抓取报文 四、获取到http请求报文: 五、http请求(request) (一)、认识URL 项…...
vscode ssh离线远程连接ubuntu调试
遇见问题: 1 ssh连接上无法启动服务器的虚拟环境; 2 ssh连接上启动服务器的虚拟环境后无法打断点; 对于问题需要参考下面连接安装python和debugy的插件拓展,并且配置json文件link。VSCode - 离线安装扩展python插件教程_vscode…...
Jenkins 通过 Version Number Plugin 自动生成和管理构建的版本号
步骤 1:安装 Version Number Plugin 登录 Jenkins 的管理界面。进入 “Manage Jenkins” -> “Manage Plugins”。在 “Available” 选项卡中搜索 “Version Number Plugin”。选中并安装插件,完成后可能需要重启 Jenkins。 步骤 2:配置…...
元学习之应用案例
现在在做元学习的时候,我们最常拿来测 试元学习技术的任务叫做少样本图像分类,简单来讲就是每一个任务都只有几张图片,每一 个类别只有几张图片。比如我们使用图1的案例为例说明。现在分类的任务是分为三个 类别,每个类别都只有两…...
网络高级(学习)2024.9.10
目录 一、Modbus简介 1.起源 2.特点 3.应用场景 二、Modbus TCP协议 1.特点 2.协议格式 3.MBAP报文头 4.功能码 5.寄存器 (1)线圈寄存器,类比为开关量,每一个bit都对应一个信号的开关状态。 (2)…...
【软件全文档】项目概要设计说明书(2024实际项目Word原件)
一、 引言 (一) 编写目的 (二) 范围 (三) 文档约定 (四) 术语 二、 项目概要 (一) 建设背景 (二) 建设目标 (三࿰…...
震惊!国产数据库厂商减少了51家!
前面文章我提到国产数据库厂商实际上大部分都不赚钱,我估计国产目前国产数据库厂商利润为正的,目前不超过5家。 而经济寒冬,融资困难,那么对于很多厂商,尤其是全靠融资的数据库厂商来讲,这将变得极其困难。…...
[AI书籍分享]<AI时代,学什么,怎么学 - 和渊>
本文由Markdown语法编辑器编辑完成。 1, 背景: 本书是一位清华大学毕业的生物学博士,和渊老师,现就职于人大附中, 是一名一线的高中生物教师. 她之前已经写过几本关于教育类的书籍,而这本书,则是她针对当前, AI时代迅猛发展的背…...
鸿蒙HarmonyOS开发:一次开发,多端部署(界面级)断点和媒体查询
文章目录 概述引入与使用流程媒体查询条件语法规则媒体类型(media-type)媒体逻辑操作(media-logic-operations)媒体特征(media-feature) 场景示例1、监听设备屏幕的方向(竖屏,横屏&a…...
1 Linux SSH安全加固_linux system-auth
 : K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...
逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...
Docker拉取MySQL后数据库连接失败的解决方案
在使用Docker部署MySQL时,拉取并启动容器后,有时可能会遇到数据库连接失败的问题。这种问题可能由多种原因导致,包括配置错误、网络设置问题、权限问题等。本文将分析可能的原因,并提供解决方案。 一、确认MySQL容器的运行状态 …...
算法刷题-回溯
今天给大家分享的还是一道关于dfs回溯的问题,对于这类问题大家还是要多刷和总结,总体难度还是偏大。 对于回溯问题有几个关键点: 1.首先对于这类回溯可以节点可以随机选择的问题,要做mian函数中循环调用dfs(i&#x…...
AT模式下的全局锁冲突如何解决?
一、全局锁冲突解决方案 1. 业务层重试机制(推荐方案) Service public class OrderService {GlobalTransactionalRetryable(maxAttempts 3, backoff Backoff(delay 100))public void createOrder(OrderDTO order) {// 库存扣减(自动加全…...
Unity-ECS详解
今天我们来了解Unity最先进的技术——ECS架构(EntityComponentSystem)。 Unity官方下有源码,我们下载源码后来学习。 ECS 与OOP(Object-Oriented Programming)对应,ECS是一种完全不同的编程范式与数据架构…...
实现p2p的webrtc-srs版本
1. 基本知识 1.1 webrtc 一、WebRTC的本质:实时通信的“网络协议栈”类比 将WebRTC类比为Linux网络协议栈极具洞察力,二者在架构设计和功能定位上高度相似: 分层协议栈架构 Linux网络协议栈:从底层物理层到应用层(如…...
